变量
基本类型
Java 编程语言是静态类型的,这意味着必须先声明所有变量,然后才能使用它们。这涉及说明变量的类型和名称,如您已经看到的那样:
int gear = 1;
这样做会告知程序存在一个名为“gear”的字段,其中包含数值数据,并且初始值为“1”。变量的数据类型决定了它可能包含的值,以及可以对其执行的操作。除此之外,Java 编程语言还支持其他七种原始数据类型。基元类型由语言预定义,并由保留关键字命名。基元值不与其他基元值共享状态。Java 编程语言支持的八种原始数据类型是:int
- byte:数据类型是 8 位有符号 2 的补码整数。它的最小值为 -128,最大值为 127(含)。数据类型可用于在大型数组中节省内存,其中内存节省实际上很重要。它们也可以用来代替它们的局限性,以帮助澄清你的代码;变量范围有限的这一事实可以作为文档的一种形式。
- short:数据类型是 16 位有符号 2 的补码整数。它的最小值为 -32,768,最大值为 32,767(含)。与 一样,同样的准则也适用:在内存节省实际上很重要的情况下,您可以使用 a 在大型数组中节省内存。
- int:默认情况下,数据类型为 32 位有符号 2 的补码整数,最小值为 -2 31,最大值为 231-1。在 Java SE 8 及更高版本中,您可以使用数据类型来表示无符号 32 位整数,其最小值为 0,最大值为 232-1。使用 Integer 类将数据类型用作无符号整数。有关详细信息,请参阅“数字类”部分。
Integer类中添加了静态方法(如 等),以支持无符号整数的算术运算。 - long:数据类型为 64 位二进制补码整数。有符号长整型的最小值为 -2 63,最大值为 263-1。在 Java SE 8 及更高版本中,您可以使用数据类型来表示无符号的 64 位长,其最小值为 0,最大值为 264-1。当您需要的值范围比 提供的值范围更宽时,请使用此数据类型。
Long类还包含 等方法,以支持无符号 long 的算术运算。 - float:数据类型为单精度 32 位 IEEE 754 浮点。它的值范围超出了本文的讨论范围,但在 Java 语言规范的浮点类型、格式和值部分中进行了指定。与 和 的建议一样,如果需要在大型浮点数数组中节省内存,请使用 a(而不是 )。此数据类型绝不应用于精确值,例如货币。为此,您需要改用 java.math.BigDecimal 类。Numbers 和 Strings 涵盖了 Java 平台提供的其他有用的类。
- double:数据类型为双精度 64 位 IEEE 754 浮点。它的值范围超出了本文的讨论范围,但在 Java 语言规范的浮点类型、格式和值部分中进行了指定。对于十进制值,此数据类型通常是默认选择。如上所述,此数据类型绝不应用于精确值,例如货币。
- boolean:数据类型只有两个可能的值:和 .将此数据类型用于跟踪 true/false 条件的简单标志。此数据类型表示一位信息,但其“大小”不是精确定义的。
boolean``true``false - char:数据类型为单个 16 位 Unicode 字符。它的最小值为 (或 0) ,最大值为 (或 65,535 包括 65,535)。 除了上面列出的八种原始数据类型外,Java 编程语言还通过 java.lang.String 类为字符串提供特殊支持。将字符串括在双引号内将自动创建一个新对象;例如。 对象是不可变的,这意味着一旦创建,它们的值就无法更改。从技术上讲,该类不是一种原始数据类型,但考虑到该语言对它的特殊支持,您可能会倾向于将其视为原始数据类型。您将在简单数据对象中了解有关该类的更多信息
默认值
在声明字段时,并不总是需要分配值。已声明但未初始化的字段将由编译器设置为合理的默认值。一般来说,此默认值为 0 或 ,具体取决于数据类型。然而,依赖这样的默认值通常被认为是糟糕的编程风格。
下图总结了上述数据类型的默认值。
| 数据类型 | 默认值 |
|---|---|
| byte | 0 |
| short | 0 |
| int | 0 |
| long | 0L |
| float | 0.0f |
| double | 0.0d |
| char | '\u0000' |
| String (或者任何对象) | null |
| boolean | false |
局部变量略有不同;编译器从不为未初始化的局部变量分配默认值。如果无法在声明局部变量的位置对其进行初始化,请确保在尝试使用它之前为其分配一个值。访问未初始化的局部变量将导致编译时错误。
文字
您可能已经注意到,在初始化基元类型的变量时不使用关键字。基元类型是语言中内置的特殊数据类型;它们不是从类创建的对象。文字是固定值的源代码表示形式;文本直接在代码中表示,无需计算。如下所示,可以将文字分配给基元类型的变量:new
boolean result = true;
char capitalC = 'C';
byte b = 100;
short s = 10000;
int i = 100000;
整数文字
如果整数文字以字母或结尾,则其类型为 ;否则,它的类型为 。建议您使用大写字母,因为小写字母很难与数字区分开来。
整型可以从文本创建超出范围的类型值。整数文字可以用以下数字系统表示:byte short int long int long int long
- 十进制:以 10 为基数,其数字由数字 0 到 9 组成;这是您每天使用的数字系统
- 十六进制:以 16 为基数,其数字由数字 0 到 9 和字母 A 到 F 组成
- 二进制:以 2 为基数,其数字由数字 0 和 1 组成(您可以在 Java SE 7 及更高版本中创建二进制文字)
对于通用编程,十进制系统可能是您唯一使用过的数字系统。但是,如果需要使用其他数字系统,以下示例显示了正确的语法。前缀表示十六进制,表示二进制:0x 0b
int decVal = 26;
// 十六进制表示26
int hexVal = 0x1a;
// 二进制表示26,
int binVal = 0b11010;
浮点文本
如果浮点文字以字母F 或 f结尾,则其类型为float ;否则,其类型为 double ,并且可以选择以字母 D或 d结尾。
浮点类型 ( 和 ) 也可以使用 E 或 e(用于科学记数法)、F 或 f(32 位浮点数)和 D 或 d(64 位双数文本;这是默认值,按照惯例省略)来表示。float double
double d1 = 123.4;
// 和d1相同,但是用科学计数法表示
double d2 = 1.234e2;
float f1 = 123.4f;
字符和字符串文本
类型的文本,可以包含任何 Unicode (UTF-16) 字符。如果您的编辑器和文件系统允许,您可以直接在代码中使用此类字符。如果没有,您可以使用“Unicode 转义”,例如(大写字母 C 带回旋符)或 (西班牙语中的 Sí Señor)。始终对文本使用“单引号”,对文本使用“双引号”。Unicode 转义序列可以在程序的其他位置使用(例如在字段名称中),而不仅仅是在文本中。char String '\u0108' "S\u00ED Se\u00F1or" char String char String
Java 编程语言还支持 和 文本的一些特殊转义序列:(退格)、(制表符)、(换行符)、(换行符)、(回车)、(双引号)、(单引号)和(反斜杠)。char String \b \t \n \f \r " ' \
还有一个特殊的文本,可以用作任何引用类型的值。 可以分配给任何变量,但基元类型的变量除外。除了测试值的存在之外,您几乎无法对值做任何事情。因此,在程序中经常用作指示某些对象不可用的标记。null``null``null``null
最后,还有一种特殊的文字,称为类文字,通过获取类型名称并附加“;例如。这是指表示类型本身的对象(类型)。.class" String.class 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;
您只能在数字之间放置下划线;不能在以下位置放置下划线:
- 在数字的开头或结尾
- 与浮点文本中的小数点相邻
- 在 或 后缀之前
FL - 在需要一串数字的位置
以下示例演示了数字文本中有效和无效的下划线位置(突出显示):
// 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_;
数组
数组是一个容器对象,它保存固定数量的单个类型的值。数组的长度是在创建数组时确定的。创建后,其长度是固定的。您已经在“Hello World!”应用程序的方法中看到了数组的示例。本节将更详细地讨论数组。
包含 10 个元素的数组。
数组中的每个项目都称为一个元素,每个元素都通过其数字索引进行访问。如上图所示,编号从 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
在实际编程情况下,您可能会使用受支持的循环构造之一来遍历数组的每个元素,而不是像前面的示例那样单独编写每一行。但是,该示例清楚地说明了数组语法。您将在“控制流”部分中了解各种循环构造 (、 和 )。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[];
然而,惯例不鼓励这种形式;括号标识数组类型,并应与类型名称一起显示。
创建、初始化和访问数组
创建数组的一种方法是使用运算符。程序中的下一条语句为一个数组分配一个具有足够内存的数组,用于 10 个整数元素,并将该数组分配给变量。new``ArrayDemo``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[][] names
在 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 声明一个元素数组。它使用该方法将数组组件的子序列复制到第二个数组中:String``System.arraycopy
class ArrayCopyDemo {
public static void main(String[] args) {
String[] copyFrom = {
"Affogato", "Americano", "Cappuccino", "Corretto", "Cortado",
"Doppio", "Espresso", "Frappucino", "Freddo", "Lungo", "Macchiato",
"Marocchino", "Ristretto" };
String[] copyTo = new String[7];
System.arraycopy(copyFrom, 2, copyTo, 0, 7);
for (String coffee : copyTo) {
System.out.print(coffee + " ");
}
}
}
该程序的输出为:
Cappuccino Corretto Cortado Doppio Espresso Frappucino Freddo
数组操作
数组是编程中使用的一个强大而有用的概念。Java SE 提供了一些方法来执行与数组相关的一些最常见操作。例如,ArrayCopyDemo 示例使用类的方法,而不是手动循环访问源数组的元素并将每个元素放入目标数组中。这是在后台执行的,使开发人员只需使用一行代码来调用该方法。arraycopy``System
为方便起见,Java SE 提供了几种方法,用于在 java.util.Arrays 类中执行数组操作(常见任务,例如复制、排序和搜索数组)。例如,可以将前面的示例修改为使用类的方法,如 ArrayCopyOfDemo 示例中所示。不同之处在于,使用该方法不需要在调用该方法之前创建目标数组,因为目标数组是由该方法返回的:copyOfRange``java.util.Arrays``copyOfRange
class ArrayCopyOfDemo {
public static void main(String[] args) {
String[] copyFrom = {
"Affogato", "Americano", "Cappuccino", "Corretto", "Cortado",
"Doppio", "Espresso", "Frappucino", "Freddo", "Lungo", "Macchiato",
"Marocchino", "Ristretto" };
String[] copyTo = java.util.Arrays.copyOfRange(copyFrom, 2, 9);
for (String coffee : copyTo) {
System.out.print(coffee + " ");
}
}
}
如您所见,该程序的输出是相同的,尽管它需要更少的代码行。请注意,该方法的第二个参数是要复制的区域的初始索引(包括该参数),而第三个参数是要复制的区域的最终索引(不包括)。在此示例中,要复制的范围不包括索引 9 处的数组元素(包含字符串)。copyOfRange``Lungo
类中的方法提供的其他一些有用的操作包括:java.util.Arrays
-
在数组中搜索特定值以获取其所在的索引 放置(方法)。
binarySearch -
比较两个数组以确定它们是否相等(方法)。
equals -
填充数组以在每个索引处放置特定值(方法)。
fill -
按升序对数组进行排序。这可以通过以下任一方式完成 依次使用该方法,或同时使用 Java SE 8 中引入的方法。并行排序 多处理器系统上的大型阵列比顺序阵列排序更快。
sort``parallelSort -
创建使用数组作为其源的流(方法)。例如,以下语句以与上一示例中相同的方式打印数组的内容:
stream``copyTojava.util.Arrays.stream(copyTo).map(coffee -> coffee + " ").forEach(System.out::print);有关流的更多信息,请参阅聚合操作。
-
将数组转换为字符串。方法 将数组的每个元素转换为字符串,用逗号分隔它们,然后 用括号将它们括起来。例如,以下语句将数组转换为字符串并打印它:
toString``copyToSystem.out.println(java.util.Arrays.toString(copyTo));此语句打印以下内容:
[Cappuccino, Corretto, Cortado, Doppio, Espresso, Frappucino, Freddo]
操作符
现在您已经学会了如何声明和初始化变量,您可能想知道如何使用它们做一些事情。学习 Java 编程语言的运算符是一个很好的起点。运算符是对一个、两个或三个操作数执行特定操作,然后返回结果的特殊符号。
当我们探索 Java 编程语言的运算符时,提前了解哪些运算符具有最高优先级可能会有所帮助。下表中的运算符按优先级顺序列出。运算符越靠近表的顶部,其优先级就越高。优先级较高的运算符在优先级相对较低的运算符之前进行评估。同一行上的运算符具有相同的优先级。当优先级相等的运算符出现在同一个表达式中时,必须有一个规则来控制哪个先计算。除赋值运算符外,所有二元运算符均按从左到右的顺序计算;赋值运算符从右到左计算。
| 运营商 | 优先 | ||
|---|---|---|---|
| 后缀 | expr++ expr-- | ||
| 元 | ++expr --expr +expr -expr ~ ! | ||
| 乘法 | * / % | ||
| 添加剂 | + - | ||
| 转变 | << >> >>> | ||
| 关系 | < > <= >= instanceof | ||
| 平等 | == != | ||
| 按位 AND | & | ||
| 按位互斥 OR | ^ | ||
| 按位(含 OR | ` | ` | |
| logical 和 | && | ||
| 逻辑 OR | ` | ` | |
| 三重的 | ? : | ||
| 分配 | `= += -= *= /= %= &= ^= | = <<= >>= >>>=` |
在通用编程中,某些运算符往往比其他运算符出现得更频繁;例如,赋值运算符 “” 比无符号右移运算符 “” 更常见。考虑到这一点,以下讨论首先关注您最有可能经常使用的运算符,最后重点介绍那些不太常见的运算符。每个讨论都附有可以编译和运行的示例代码。研究它的输出将有助于巩固你刚刚学到的东西。=``>>>
赋值、算术和一元运算符
简单赋值运算符
您将遇到的最常见的运算符之一是简单的赋值运算符 “”。您在 Bicycle 类中看到了这个运算符;它将右边的值分配给左边的操作数:=
int cadence = 0;
int speed = 0;
int gear = 1;
此运算符还可用于对象以分配对象引用,如创建对象中所述。
算术运算符
Java 编程语言提供了执行加法、减法、乘法和除法的运算符。你很有可能通过基础数学中的对应物来识别它们。唯一可能看起来很新的符号是 “”,它将一个操作数除以另一个操作数,并返回余数作为其结果。%
| 算子 | 描述 |
|---|---|
+ | 加法运算符(也用于字符串连接) |
- | 减法运算符 |
* | 乘法运算符 |
/ | 分部运算符 |
% | 余数运算符 |
以下程序 ArithmeticDemo 测试算术运算符。
class ArithmeticDemo {
public static void main (String[] args) {
int result = 1 + 2;
// result is now 3
System.out.println("1 + 2 = " + result);
int original_result = result;
result = result - 1;
// result is now 2
System.out.println(original_result + " - 1 = " + result);
original_result = result;
result = result * 2;
// result is now 4
System.out.println(original_result + " * 2 = " + result);
original_result = result;
result = result / 2;
// result is now 2
System.out.println(original_result + " / 2 = " + result);
original_result = result;
result = result + 8;
// result is now 10
System.out.println(original_result + " + 8 = " + result);
original_result = result;
result = result % 7;
// result is now 3
System.out.println(original_result + " % 7 = " + result);
}
}
此程序打印以下内容:
1 + 2 = 3
3 - 1 = 2
2 * 2 = 4
4 / 2 = 2
2 + 8 = 10
10 % 7 = 3
您还可以将算术运算符与简单赋值运算符组合在一起,以创建复合赋值。例如,两者都将 的值递增 1。x+=1;``x=x+1;``x
该运算符还可用于将两个字符串连接(连接)在一起,如以下 ConcatDemo 程序所示:+
class ConcatDemo {
public static void main(String[] args){
String firstString = "This is";
String secondString = " a concatenated string.";
String thirdString = firstString+secondString;
System.out.println(thirdString);
}
}
在此程序结束时,变量包含“This is a concatenated string.”,该字符串将打印为标准输出。thirdString
一元运算符
一元运算符只需要一个操作数;它们执行各种操作,例如将值递增/递减 1、否定表达式或反转布尔值。
| 算子 | 描述 |
|---|---|
+ | 一元加运算符;表明 正值(数字为 但是,没有这个是积极的) |
- | 一元减号运算符;否定 表达式 |
++ | 增量运算符;增量 值乘以 1 |
-- | 递减运算符;递减 值乘以 1 |
! | 逻辑补码运算符; 反转布尔值的值 |
以下程序 UnaryDemo 测试一元运算符:
class UnaryDemo {
public static void main(String[] args) {
int result = +1;
// result is now 1
System.out.println(result);
result--;
// result is now 0
System.out.println(result);
result++;
// result is now 1
System.out.println(result);
result = -result;
// result is now -1
System.out.println(result);
boolean success = false;
// false
System.out.println(success);
// true
System.out.println(!success);
}
}
递增/递减运算符可以应用于操作数之前(前缀)或之后(后缀)。代码 和 都将以递增 1 结束。唯一的区别是前缀版本 () 的计算结果为递增值,而后缀版本 () 的计算结果为原始值。如果您只是执行简单的递增/递减,那么选择哪个版本并不重要。但是,如果在较大表达式的一部分中使用此运算符,则选择的运算符可能会产生显著差异。result++;``++result;``result``++result``result++
以下程序 PrePostDemo 演示了前缀/后缀一元递增运算符:
class PrePostDemo {
public static void main(String[] args){
int i = 3;
i++;
// prints 4
System.out.println(i);
++i;
// prints 5
System.out.println(i);
// prints 6
System.out.println(++i);
// prints 6
System.out.println(i++);
// prints 7
System.out.println(i);
}
}
相等、关系和条件运算符
相等运算符和关系运算符
相等运算符和关系运算符确定一个操作数是大于、小于、等于还是不等于另一个操作数。这些运算符中的大多数可能看起来也很熟悉。请记住,在测试两个基元值是否相等时,必须使用 “”,而不是 “”。==``=
== equal to
!= not equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
以下程序 ComparisonDemo 测试比较运算符:
class ComparisonDemo {
public static void main(String[] args){
int value1 = 1;
int value2 = 2;
if(value1 == value2)
System.out.println("value1 == value2");
if(value1 != value2)
System.out.println("value1 != value2");
if(value1 > value2)
System.out.println("value1 > value2");
if(value1 < value2)
System.out.println("value1 < value2");
if(value1 <= value2)
System.out.println("value1 <= value2");
}
}
输出:
value1 != value2
value1 < value2
value1 <= value2
条件运算符
and 运算符对两个布尔表达式执行 Conditional-AND 和 Conditional-OR 运算。**这些算子表现出“短路”行为,这意味着仅在需要时才评估第二个操作数。&&``||
&& Conditional-AND
|| Conditional-OR
以下程序 ConditionalDemo1 测试这些运算符:
class ConditionalDemo1 {
public static void main(String[] args){
int value1 = 1;
int value2 = 2;
if((value1 == 1) && (value2 == 2))
System.out.println("value1 is 1 AND value2 is 2");
if((value1 == 1) || (value2 == 1))
System.out.println("value1 is 1 OR value2 is 1");
}
}
另一个条件运算符是 ,可以将其视为语句的简写(在本课的“控制流语句”部分中讨论)。此运算符也称为三元运算符,因为它使用三个操作数。在以下示例中,此运算符应读作:“如果为 ,则将 的值赋值给 。否则,请将值赋给 。?:``if-then-else``someCondition``true``value1``result``value2``result
以下程序 ConditionalDemo2 测试运算符:?:
class ConditionalDemo2 {
public static void main(String[] args){
int value1 = 1;
int value2 = 2;
int result;
boolean someCondition = true;
result = someCondition ? value1 : value2;
System.out.println(result);
}
}
因为是真的,所以这个程序将“1”打印到屏幕上。如果运算符使代码更具可读性,请使用运算符而不是语句;例如,当表达式紧凑且没有副作用(例如赋值)时。someCondition``?:``if-then-else
类型比较运算符 instanceof
运算符将对象与指定类型进行比较。可以使用它来测试对象是类的实例、子类的实例还是实现特定接口的类的实例。instanceof
以下程序 InstanceofDemo 定义一个父类 (named )、一个简单接口 (named ) 和一个子类 (named ),该子类继承自父类并实现该接口。Parent``MyInterface``Child
class InstanceofDemo {
public static void main(String[] args) {
Parent obj1 = new Parent();
Parent obj2 = new Child();
System.out.println("obj1 instanceof Parent: "
+ (obj1 instanceof Parent));
System.out.println("obj1 instanceof Child: "
+ (obj1 instanceof Child));
System.out.println("obj1 instanceof MyInterface: "
+ (obj1 instanceof MyInterface));
System.out.println("obj2 instanceof Parent: "
+ (obj2 instanceof Parent));
System.out.println("obj2 instanceof Child: "
+ (obj2 instanceof Child));
System.out.println("obj2 instanceof MyInterface: "
+ (obj2 instanceof MyInterface));
}
}
class Parent {}
class Child extends Parent implements MyInterface {}
interface MyInterface {}
输出:
obj1 instanceof Parent: true
obj1 instanceof Child: false
obj1 instanceof MyInterface: false
obj2 instanceof Parent: true
obj2 instanceof Child: true
obj2 instanceof MyInterface: true
使用运算符时,请记住,这不是任何事物的实例。instanceof``null
按位和位移运算符
Java 编程语言还提供了对整数类型执行按位和位移运算的运算符。本节中讨论的运算符不太常用。因此,它们的覆盖范围很短;其目的是让您知道这些运算符的存在。
一元按位补码运算符 “” 反转位模式;它可以应用于任何整数类型,使每个“0”成为“1”,使每个“1”成为“0”。例如,a 包含 8 位;将此运算符应用于位模式为“00000000”的值会将其模式更改为“11111111”。~ byte
有符号的左移运算符 “” 将位模式向左移动,有符号右移运算符 “” 将位模式向右移。位模式由左手操作数给出,要移动的位置数由右手操作数给出。无符号右移运算符 “” 将零移到最左边的位置,而后面最左边的位置取决于符号扩展。<< >> >>> ">>"
按位运算符执行按位 AND 运算。&
按位运算符执行按位互斥 OR 运算。^
按位运算符执行按位非独占 OR 运算。|
以下程序 BitDemo 使用按位 AND 运算符将数字“2”打印到标准输出。
class BitDemo {
public static void main(String[] args) {
int bitmask = 0x000F;
int val = 0x2222;
// prints "2"
System.out.println(val & bitmask);
}
运算符摘要
以下快速参考总结了 Java 编程语言支持的运算符。
简单赋值运算符
= Simple assignment operator
算术运算符
+ Additive operator (also used
for String concatenation)
- Subtraction operator
* Multiplication operator
/ Division operator
% Remainder operator
一元运算符
+ Unary plus operator; indicates
positive value (numbers are
positive without this, however)
- Unary minus operator; negates
an expression
++ Increment operator; increments
a value by 1
-- Decrement operator; decrements
a value by 1
! Logical complement operator;
inverts the value of a boolean
相等和关系运算符
== Equal to
!= Not equal to
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equal to
条件运算符
&& Conditional-AND
|| Conditional-OR
?: Ternary (shorthand for
if-then-else statement)
类型比较运算符
instanceof Compares an object to
a specified type
按位和位移运算符
~ Unary bitwise complement
<< Signed left shift
>> Signed right shift
>>> Unsigned right shift
& Bitwise AND
^ Bitwise exclusive OR
| Bitwise inclusive OR
表达式、语句和代码块
现在您已经了解了变量和运算符,是时候了解表达式、语句和块了。运算符可用于构建计算值的表达式;表达式是语句的核心组成部分;语句可以分组到块中。
表达式
表达式是由变量、运算符和方法调用组成的构造,这些构造根据语言的语法构造,其计算结果为单个值。您已经看到了表达式示例,下面以粗体显示:
int cadence = 0;
anArray[0] = 100;
System.out.println( "Element 1 at index 0: " + anArray[0] );
int result = 1 + 2; // result is now 3
if (value1 == value2)
System.out.println( "value1 == value2" );
表达式返回的值的数据类型取决于表达式中使用的元素。表达式返回一个,因为赋值运算符返回的数据类型与其左侧操作数相同的值;在本例中,是 .从其他表达式中可以看出,表达式也可以返回其他类型的值,例如 或 。cadence = 0``int``cadence``int``boolean``String
Java 编程语言允许您从各种较小的表达式构造复合表达式,只要表达式的一部分所需的数据类型与另一部分的数据类型匹配即可。下面是一个复合表达式的示例:
1 * 2 * 3
在这个特定示例中,计算表达式的顺序并不重要,因为乘法的结果与顺序无关;无论您以何种顺序应用乘法,结果始终是相同的。但是,并非所有表达式都是如此。例如,以下表达式给出不同的结果,具体取决于您是先执行加法运算还是除法运算:
x + y / 100 // ambiguous
您可以使用平衡括号( 和 )准确指定表达式的计算方式。例如,要使前面的表达式明确无误,可以编写以下内容:
(x + y) / 100 // unambiguous, recommended
如果未明确指示要执行的操作的顺序,则顺序由分配给表达式中使用的运算符的优先级确定。首先评估具有较高优先级的运算符。例如,除法运算符的优先级高于加法运算符。因此,以下两个语句是等效的:
x + y / 100
x + (y / 100) // unambiguous, recommended
编写复合表达式时,要明确,并用括号指示应首先计算哪些运算符。这种做法使代码更易于阅读和维护。
语句
语句大致相当于自然语言中的句子。语句构成一个完整的执行单元。以下类型的表达式可以通过用分号 () 终止表达式来制作成语句。;
- 赋值表达式
- 对 或
++``-- - 方法调用
- 对象创建表达式
此类语句称为表达式语句。下面是表达式语句的一些示例。
// assignment statement
aValue = 8933.234;
// increment statement
aValue++;
// method invocation statement
System.out.println("Hello World!");
// object creation statement
Bicycle myBike = new Bicycle();
除了表达式语句之外,还有另外两种语句:声明语句和控制流语句。声明语句声明变量。您已经看到许多声明语句的示例:
// declaration statement
double aValue = 8933.234;
最后,控制流语句调节语句的执行顺序。您将在下一节“控制流语句”中了解控制流语句
块
块是平衡大括号之间的一组零个或多个语句,可以在允许单个语句的任何位置使用。以下示例 BlockDemo 说明了块的用法:
class BlockDemo {
public static void main(String[] args) {
boolean condition = true;
if (condition) { // begin block 1
System.out.println("Condition is true.");
} // end block one
else { // begin block 2
System.out.println("Condition is false.");
} // end block 2
}
}
控制流
if-then 和 if-then-else 语句
声明if-then
该语句是所有控制流语句中最基本的语句。它告诉程序仅在特定测试的计算结果为 时才执行代码的某个部分。例如,只有当自行车已经在运动时,该类才允许制动器降低自行车的速度。该方法的一种可能实现如下:if-then``true``Bicycle``applyBrakes
void applyBrakes() {
// the "if" clause: bicycle must be moving
if (isMoving){
// the "then" clause: decrease current speed
currentSpeed--;
}
}
如果此测试的计算结果为(表示自行车未运动),则控制跳转到语句的末尾。false``if-then
此外,左大括号和右大括号是可选的,前提是“then”子句仅包含一个语句:
void applyBrakes() {
// same as above, but without braces
if (isMoving)
currentSpeed--;
}
决定何时省略大括号是个人品味的问题。省略它们会使代码更加脆弱。如果稍后在“then”子句中添加第二个语句,一个常见的错误是忘记添加新需要的大括号。编译器无法捕获此类错误;你只会得到错误的结果。
声明if-then-else
当 “if” 子句的计算结果为 时,该语句提供辅助执行路径。如果在自行车未运动时踩下制动器,则可以在方法中使用语句来采取一些操作。在这种情况下,操作是简单地打印一条错误消息,说明自行车已经停止。if-then-else``false``if-then-else``applyBrakes
void applyBrakes() {
if (isMoving) {
currentSpeed--;
} else {
System.err.println("The bicycle has already stopped!");
}
}
以下程序 IfElseDemo 根据测试分数的值分配等级:A 表示 90% 或以上的分数,B 表示 80% 或以上的分数,依此类推。
class IfElseDemo {
public static void main(String[] args) {
int testscore = 76;
char grade;
if (testscore >= 90) {
grade = 'A';
} else if (testscore >= 80) {
grade = 'B';
} else if (testscore >= 70) {
grade = 'C';
} else if (testscore >= 60) {
grade = 'D';
} else {
grade = 'F';
}
System.out.println("Grade = " + grade);
}
}
程序的输出为:
Grade = C
您可能已经注意到,的值可以满足复合语句中的多个表达式:和 。但是,一旦满足条件,就会执行相应的语句,并且不会计算其余条件。testscore``76 >= 70``76 >= 60``(grade = 'C';)
#@ switch 语句
与 和 语句不同,该语句可以有多个可能的执行路径。A 使用 、 、 和 基元数据类型。它还适用于枚举**类型(在枚举类型中讨论)、String 类以及包装某些基元类型的一些特殊类:Character、Byte、Short 和 Integer(在 Numbers 和 Strings 中讨论)。if-then``if-then-else``switch``switch``byte``short``char``int
下面的代码示例 SwitchDemo 声明一个名称,其值表示一个月。该代码使用 语句根据 的值 显示月份的名称。int``month``month``switch
public class SwitchDemo {
public static void main(String[] args) {
int month = 8;
String monthString;
switch (month) {
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
case 3: monthString = "March";
break;
case 4: monthString = "April";
break;
case 5: monthString = "May";
break;
case 6: monthString = "June";
break;
case 7: monthString = "July";
break;
case 8: monthString = "August";
break;
case 9: monthString = "September";
break;
case 10: monthString = "October";
break;
case 11: monthString = "November";
break;
case 12: monthString = "December";
break;
default: monthString = "Invalid month";
break;
}
System.out.println(monthString);
}
}
在这种情况下,将打印到标准输出。August
语句的主体称为开关块。块中的语句可以用一个或多个 或 标签进行标记。该语句计算其表达式,然后执行匹配标签后面的所有语句。switch``switch``case``default``switch``case
您还可以使用语句显示月份名称:if-then-else
int month = 8;
if (month == 1) {
System.out.println("January");
} else if (month == 2) {
System.out.println("February");
}
... // and so on
决定是使用语句还是语句基于可读性和语句正在测试的表达式。语句可以基于值或条件范围测试表达式,而语句仅基于单个整数、枚举值或对象测试表达式。if-then-else``switch``if-then-else``switch``String
另一个有趣的点是声明。每个语句都终止结束结束语句。控制流继续,块后面的第一个语句。这些语句是必需的,因为如果没有它们,块中的语句就会失败:匹配标签之后的所有语句都会按顺序执行,而不管后续标签的表达式如何,直到遇到语句。程序 SwitchDemoFallThrough 显示块中失败的语句。该程序显示与整数对应的月份以及一年中的后续月份:break``break``switch``switch``break``switch``case``case``break``switch``month
public class SwitchDemoFallThrough {
public static void main(String[] args) {
java.util.ArrayList<String> futureMonths =
new java.util.ArrayList<String>();
int month = 8;
switch (month) {
case 1: futureMonths.add("January");
case 2: futureMonths.add("February");
case 3: futureMonths.add("March");
case 4: futureMonths.add("April");
case 5: futureMonths.add("May");
case 6: futureMonths.add("June");
case 7: futureMonths.add("July");
case 8: futureMonths.add("August");
case 9: futureMonths.add("September");
case 10: futureMonths.add("October");
case 11: futureMonths.add("November");
case 12: futureMonths.add("December");
break;
default: break;
}
if (futureMonths.isEmpty()) {
System.out.println("Invalid month number");
} else {
for (String monthName : futureMonths) {
System.out.println(monthName);
}
}
}
}
This is the output from the code:
August
September
October
November
December
Technically, the final is not required because flow falls out of the statement. Using a is recommended so that modifying the code is easier and less error prone. The section handles all values that are not explicitly handled by one of the sections.break``switch``break``default``case
The following code example, SwitchDemo2, shows how a statement can have multiple labels. The code example calculates the number of days in a particular month:case
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
switch (month) {
case 1: case 3: case 5:
case 7: case 8: case 10:
case 12:
numDays = 31;
break;
case 4: case 6:
case 9: case 11:
numDays = 30;
break;
case 2:
if (((year % 4 == 0) &&
!(year % 100 == 0))
|| (year % 400 == 0))
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("Invalid month.");
break;
}
System.out.println("Number of Days = "
+ numDays);
}
}
这是代码的输出:
Number of Days = 29
在 switch 语句中使用字符串
在 Java SE 7 及更高版本中,可以在语句的表达式中使用对象。下面的代码示例 StringSwitchDemo 根据 named 的值显示月份的数字:String``switch``String``month
public class StringSwitchDemo {
public static int getMonthNumber(String month) {
int monthNumber = 0;
if (month == null) {
return monthNumber;
}
switch (month.toLowerCase()) {
case "january":
monthNumber = 1;
break;
case "february":
monthNumber = 2;
break;
case "march":
monthNumber = 3;
break;
case "april":
monthNumber = 4;
break;
case "may":
monthNumber = 5;
break;
case "june":
monthNumber = 6;
break;
case "july":
monthNumber = 7;
break;
case "august":
monthNumber = 8;
break;
case "september":
monthNumber = 9;
break;
case "october":
monthNumber = 10;
break;
case "november":
monthNumber = 11;
break;
case "december":
monthNumber = 12;
break;
default:
monthNumber = 0;
break;
}
return monthNumber;
}
public static void main(String[] args) {
String month = "August";
int returnedMonthNumber =
StringSwitchDemo.getMonthNumber(month);
if (returnedMonthNumber == 0) {
System.out.println("Invalid month");
} else {
System.out.println(returnedMonthNumber);
}
}
}
此代码的输出为 .8
将表达式中的表达式与与每个标签关联的表达式进行比较,就像使用了 String.equals 方法一样。为了使示例接受任何月份(无论大小写如何),将转换为小写(使用 toLowerCase 方法),并且与标签关联的所有字符串都为小写。String``switch``case``StringSwitchDemo``month``case
注意:本示例检查语句中的表达式是否为 。确保任何语句中的表达式都不为 null,以防止抛出 a。switch``null``switch``NullPointerException
while 和 do-while 语句
当特定条件为 时,该语句会持续执行语句块。其语法可以表示为:while``true
while (expression) {
statement(s)
}
该语句计算表达式,表达式必须返回一个值。如果表达式的计算结果为 ,则该语句将执行块中的语句。该语句继续测试表达式并执行其块,直到表达式的计算结果为 。使用该语句打印从 1 到 10 的值可以完成,如以下 WhileDemo 程序所示:while``boolean``true``while``while``while``false``while
class WhileDemo {
public static void main(String[] args){
int count = 1;
while (count < 11) {
System.out.println("Count is: " + count);
count++;
}
}
}
您可以使用以下语句实现无限循环:while
while (true){
// your code goes here
}
Java 编程语言还提供了一个语句,可以表示如下:do-while
do {
statement(s)
} while (expression);
and 之间的区别在于它在循环的底部而不是顶部计算其表达式。因此,块中的语句始终至少执行一次,如以下 DoWhileDemo 程序所示:do-while``while``do-while``do
class DoWhileDemo {
public static void main(String[] args){
int count = 1;
do {
System.out.println("Count is: " + count);
count++;
} while (count < 11);
}
}
for 语句
该语句提供了一种紧凑的方式来循环访问一系列值。程序员通常将其称为“for 循环”,因为它会重复循环直到满足特定条件。声明的一般形式可以表达如下:for``for
for (initialization; termination;
increment) {
statement(s)
}
使用此版本的语句时,请记住:for
- 初始化表达式初始化循环;当循环开始时,它执行一次。
- 当终止表达式的计算结果为 时,循环终止。
false - 增量表达式在每次迭代后通过循环调用;此表达式递增或递减值是完全可以接受的。
以下程序 ForDemo 使用语句的一般形式将数字 1 到 10 打印到标准输出:for
class ForDemo {
public static void main(String[] args){
for(int i=1; i<11; i++){
System.out.println("Count is: " + i);
}
}
}
该程序的输出为:
Count is: 1
Count is: 2
Count is: 3
Count is: 4
Count is: 5
Count is: 6
Count is: 7
Count is: 8
Count is: 9
Count is: 10
请注意代码如何在初始化表达式中声明变量。此变量的作用域从其声明扩展到由语句控制的块的末尾,因此它也可以用于终止和增量表达式。如果在循环之外不需要控制语句的变量,则最好在初始化表达式中声明该变量。名称 、 和 通常用于控制循环;在初始化表达式中声明它们会限制它们的生命周期并减少错误。for``for``i``j``k``for
循环的三个表达式是可选的;可以按如下方式创建无限循环:for
// infinite loop
for ( ; ; ) {
// your code goes here
}
该语句还有另一种形式,用于通过 Collections 和数组进行迭代 此形式有时称为增强的 for 语句,可用于使循环更紧凑且更易于阅读。为了演示,请考虑以下数组,其中包含数字 1 到 10:for
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
以下程序 EnhancedForDemo 使用 enhanced 遍历数组:for
class EnhancedForDemo {
public static void main(String[] args){
int[] numbers =
{1,2,3,4,5,6,7,8,9,10};
for (int item : numbers) {
System.out.println("Count is: " + item);
}
}
}
在此示例中,该变量保存 numbers 数组中的当前值。此程序的输出与之前相同:item
Count is: 1
Count is: 2
Count is: 3
Count is: 4
Count is: 5
Count is: 6
Count is: 7
Count is: 8
Count is: 9
Count is: 10
我们建议尽可能使用这种形式的声明,而不是一般形式。for
分支语句
声明break
该语句有两种形式:标记和未标记。您在前面对该语句的讨论中看到了未标记的表单。还可以使用 unlabeled 来终止 、 或循环,如以下 BreakDemo 程序所示:break``switch``break``for``while``do-while
class BreakDemo {
public static void main(String[] args) {
int[] arrayOfInts =
{ 32, 87, 3, 589,
12, 1076, 2000,
8, 622, 127 };
int searchfor = 12;
int i;
boolean foundIt = false;
for (i = 0; i < arrayOfInts.length; i++) {
if (arrayOfInts[i] == searchfor) {
foundIt = true;
break;
}
}
if (foundIt) {
System.out.println("Found " + searchfor + " at index " + i);
} else {
System.out.println(searchfor + " not in the array");
}
}
}
该程序在数组中搜索数字 12。该语句(以粗体显示)在找到该值时终止循环。然后,控制流在循环后转移到语句。该程序的输出为:break``for``for
Found 12 at index 4
未标记的语句终止最内层的 、 、 或语句,但标记的语句终止外部语句。下面的程序 BreakWithLabelDemo 与前面的程序类似,但使用嵌套循环在二维数组中搜索值。找到该值后,带标签的将终止外部循环(标记为“search”):break``switch``for``while``do-while``break``for``break``for
class BreakWithLabelDemo {
public static void main(String[] args) {
int[][] arrayOfInts = {
{ 32, 87, 3, 589 },
{ 12, 1076, 2000, 8 },
{ 622, 127, 77, 955 }
};
int searchfor = 12;
int i;
int j = 0;
boolean foundIt = false;
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length;
j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search;
}
}
}
if (foundIt) {
System.out.println("Found " + searchfor + " at " + i + ", " + j);
} else {
System.out.println(searchfor + " not in the array");
}
}
}
这是程序的输出。
Found 12 at 1, 0
该语句终止带标签的语句;它不会将控制流转移到标签上。控制流将紧跟在标记(终止)语句之后的语句中。break
声明continue
该语句跳过 、 或 循环的当前迭代。未标记的窗体跳到最内层循环主体的末尾,并计算控制循环的表达式。以下程序 ContinueDemo 单步执行 ,计算字母“p”的出现次数。如果当前字符不是 p,则该语句将跳过循环的其余部分,并继续执行下一个字符。如果是“p”,程序将递增字母数。continue``for``while``do-while``boolean``String``continue
class ContinueDemo {
public static void main(String[] args) {
String searchMe = "peter piper picked a " + "peck of pickled peppers";
int max = searchMe.length();
int numPs = 0;
for (int i = 0; i < max; i++) {
// interested only in p's
if (searchMe.charAt(i) != 'p')
continue;
// process p's
numPs++;
}
System.out.println("Found " + numPs + " p's in the string.");
}
}
以下是该程序的输出:
Found 9 p's in the string.
若要更清楚地看到此效果,请尝试删除该语句并重新编译。当您再次运行该程序时,计数将是错误的,说它找到了 35 个 p 而不是 9。continue
带标签的语句跳过标有给定标签的外部循环的当前迭代。以下示例程序 , 使用嵌套循环在另一个字符串中搜索子字符串。需要两个嵌套循环:一个用于循环访问子字符串,另一个循环访问正在搜索的字符串。以下程序 ContinueWithLabelDemo 使用标记形式的 continue 跳过外部循环中的迭代。continue ContinueWithLabelDemo
class ContinueWithLabelDemo {
public static void main(String[] args) {
String searchMe = "Look for a substring in me";
String substring = "sub";
boolean foundIt = false;
int max = searchMe.length() -
substring.length();
test:
for (int i = 0; i <= max; i++) {
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
}
foundIt = true;
break test;
}
System.out.println(foundIt ? "Found it" : "Didn't find it");
}
}
这是该程序的输出。
Found it
声明return
最后一个分支语句是语句。语句从当前方法退出,控制流返回到调用该方法的位置。该语句有两种形式:一种返回值,另一种不返回值。要返回一个值,只需将该值(或计算该值的表达式)放在关键字之后即可。
return ++count;
返回值的数据类型必须与方法声明的返回值的类型匹配。当声明一个方法时,使用 that 不返回值的形式。void return
return;
类和对象课程将涵盖您需要了解的有关编写方法的所有信息。