本文编写于 131 天前,最后修改于 131 天前,其中某些信息可能已经过时。

Java的基本语法

每一种编程语言都有一套自己的语法规范,Java语言也不例外,同样需要遵从一定的语法规范,如代码的书写、标识符的定义、关键字的应用等。因此要学好Java语言,首先需要熟悉它的基本语法。

Java代码的基本格式

Java中的程序代码都必须放在一个类中,初学者可以简单地把类理解为一个Java程序。类需要使用class关键字定义,在class前面可以有一些修饰符,格式如下:

修饰符 class 类名 {
    程序代码
}

在编写Java代码时,需要特别注意几个关键:

  • Java中的程序代码可分为结构定义语句和功能执行语句,其中,结构定义语句用于声明一个类或方法,功能执行语句用于实现具体的功能。每条功能执行语句的最后都必须用分号(;)结束。如下面的语句:
System.out.println("这是第一个Java 程序!");

值得注意的是,在程序中不要将英文的分号(;)误写成中文的分号(;),如果写成中文的分号,编译器会报告“illegalcharacter”(非法字符)这样的错误信息。

  • Java语言是严格区分大小写的。在定义类时,不能将class写成Class,否则编译会报错。程序中定义一个computer的同时,还可以定义一个Computer,computer和Computer是两个完全不同的符号,在使用时务必注意。
  • 在编写Java代码时,为了便于阅读,通常会使用一种良好的格式进行排版,但这并不是必需的,我们也可以在两个单词或符号之间任意的换行,例如下面这段代码的编排方式也是可以的。
public class HelloWorld {public static void
main(String [
] args){System.out.println("这是第一个Java 程序!");}}

虽然Java没有严格要求用什么样的格式来编排程序代码,但是,出于可读性的考虑,应该让自己编写的程序代码整齐美观、层次清晰,通常会使用下面这种形式:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("这是第一个Java 程序!");
    }
}
  • Java程序中一句连续的字符串不能分开在两行中书写,例如,下面这条语句在编译时将会出错:
System.out.println("这是第一个
Java 程序!");

如果为了便于阅读,想将一个太长的字符串分在两行中书写,可以先将这个字符串分成两个字符串,然后用加号(+)将这两个字符串连起来,在加号(+)处断行。上面的语句可以修改成如下形式:

System.out.println("这是第一个"+
"Java 程序!");

Java中的注释

在编写程序时,为了使代码易于阅读,通常会在实现功能的同时为代码加一些注释。注释是对程序的某个功能或者某行代码的解释说明,它只在Java源文件中有效,在编译程序时编译器会忽略这些注释信息,不会将其编译到class字节码文件中去。

Java中的注释有三种类型,具体如下。

  • 单行注释

单行注释通常用于对程序中的某一行代码进行解释,用符号“//”表示,“//”后面为被注释的内容,具体示例如下:

int c = 10; //定义一个整型变量
  • 多行注释

多行注释顾名思义就是在注释中的内容可以为多行,它以符号“/”开头,以符号“/”结尾,多行注释具体示例如下:

/*int c = 10;
int x = 5; */
  • 文档注释

文档注释是以“/*”开头,并在注释内容末尾以“/”结束。文档注释是对一段代码概括的解释说明,可以使用javadoc命令将文档注释提取出来生成帮助文档,关于这点将在后面的章节做详细讲解。

Java中的标识符

在编程过程中,经常需要在程序中定义一些符号来标记一些名称,如包名、类名、方法名、参数名、变量名等,这些符号被称为标识符。标识符可以由任意顺序的大小写字母、数字、下划线(_)和美元符号($)组成,但标识符不能以数字开头,不能是Java中的关键字。

下面的这些标识符都是合法的。

username
username123
user_name
_userName
$ username

注意,下面的这些标识符都是不合法的!

123username
class
98.3
Hello World

在Java程序中定义的标识符必须要严格遵守上面列出的规范,否则程序在编译时会报错。除了上面列出的规范,为了增强代码的可读性,建议初学者在定义标识符时还应该遵循以下规则:

  • 包名所有字母一律小写,例如cn.itcast.test。
  • 类名和接口名每个单词的首字母都要大写,例如ArrayList、Iterator。
  • 常量名所有字母都大写,单词之间用下划线连接,例如DAY_OF_MONTH。
  • 变量名和方法名的第一个单词首字母小写,从第二个单词开始每个单词首字母大写,例如lineNumber、getLineNumber。
  • 在程序中,应该尽量使用有意义的英文单词来定义标识符,使得程序便于阅读。
  • 例如使用userName表示用户名,passWord表示密码。

Java中的关键字

关键字是编程语言里事先定义好并赋予了特殊含义的单词,也称作保留字。和其他语言一样,Java中保留了许多关键字,例如,class、public等,下面列举的是Java中所有的关键字。

abstract  boolean  break  byte  case
catch  char  const  class  continue
default  do  double  else  extends
false  final  finally  float  for
goto  if  implements  import  instanceof
int  interface  long  native  new
null  package  private  protected  public
return  short  static  strictfp  super
switch  this  throw  throws  transient
true  try  void  volatile  while
synchronized

上面列举的关键字中,每个关键字都有特殊的作用。例如package关键字用于包的声明,import关键字用于引入包,class关键字用于类的声明。在本书后面的章节将逐步对其他关键字进行讲解,在此没有必要对所有关键字进行记忆,只需要了解即可。

使用Java关键字时,有几个值得注意的地方:

  • 所有的关键字都是小写的。
  • 程序中的标识符不能以关键字命名。

Java中的常量

常量就是在程序中固定不变的值,是不能改变的数据。例如数字1、字符’a’、浮点数3.2等。在Java中,常量包括整型常量、浮点数常量、布尔常量、字符常量等。

  • 整型常量

整型常量是整数类型的数据,有二进制、八进制、十进制和十六进制4种表示形式,具体表示形式如下。

二进制:由数字0和1组成的数字序列。在JDK7.0中允许使用字面值来表示二进制数,前面要以0b 或0B 开头,目的是为了和十进制进行区分,如0b01101100、0B10110101。

八进制:以0开头并且其后由0~7范围内(包括0和7)的整数组成的数字序列,如0342。

十进制:由数字0~9范围内(包括0和9)的整数组成的数字序列。如198。

十六进制:以0x或者0X开头并且其后由0~9、A~F(包括0和9、A 和F)组成的数字序列,如0x25AF。

需要注意的是,在程序中为了标明不同的进制,数据都有特定的标识,八进制必须以0开头,如0711、0123;十六进制必须以0x或0X开头,如0xaf3、0Xff;整数以十进制表示时,第一位不能是0,0本身除外。例如十进制的127,用二进制表示为01111111,用八进制表示为0177,用十六进制表示为0x7F或者0X7F。

  • 浮点数常量

浮点数常量就是在数学中用到的小数,分为float单精度浮点数和double双精度浮点数两种类型。其中,单精度浮点数后面以F或f结尾,而双精度浮点数则以D 或d结尾。当然,在使用浮点数时也可以在结尾处不加任何的后缀,此时虚拟机会默认为double双精度浮点数。浮点数常量还可以通过指数形式来表示。具体示例如下:

2e3f 3.6d 0f 3.84d 5.022e+23f

上述列出的浮点数常量中用到的e和f,初学者可能会感到困惑,在后面将会详细介绍。

  • 字符常量

字符常量用于表示一个字符,一个字符常量要用一对英文半角格式的单引号’ ‘引起来,它可以是英文字母、数字、标点符号以及由转义序列来表示的特殊字符。具体示例如下:

'a' '1' '&' '\r' '\u0000'

上面的示例中,’ u0000’表示一个空白字符,即在单引号之间没有任何字符。之所以能这样表示,是因为Java采用的是Unicode字符集,Unicode字符以u开头,空白字符在Unicode码表中对应的值为’u0000’。

  • 字符串常量

字符串常量用于表示一串连续的字符,一个字符串常量要用一对英文半角格式的双引号””引起来,具体示例如下:

"HelloWorld" "123" "Welcome \n XXX" ""

一个字符串可以包含一个字符或多个字符,也可以不包含任何字符,即长度为零。

  • 布尔常量

布尔常量即布尔型的两个值true和false,该常量用于区分一个事物的真与假。

  • null常量

null常量只有一个值null,表示对象的引用为空。关于null常量后面将会详细介绍。

Java中的变量

变量的定义

在程序运行期间,随时可能产生一些临时数据,应用程序会将这些数据保存在一些内存单元中,每个内存单元都用一个标识符来标识。这些内存单元被称为变量,定义的标识符就是变量名,内存单元中存储的数据就是变量的值。接下来,通过具体的代码来学习变量的定义。

int x = 0,y;
y = x + 3;

上面的代码中,第一行代码的作用是定义了两个变量x和y,也就相当于分配了两块内存单元,在定义变量的同时为变量x分配了一个初始值0,而变量y没有分配初始值,变量x和y在内存中的状态如图2-2所示。

第二行代码的作用是为变量赋值,在执行第二行代码时,程序首先取出变量x的值,与3相加后,将结果赋值给变量y,此时变量x和y在内存中的状态发生了变化,如图2-3所示。

变量的数据类型

Java是一门强类型的编程语言,它对变量的数据类型有严格的限定。在定义变量时必须声明变量的类型,在为变量赋值时必须赋予和变量同一种类型的值,否则程序会报错。

在Java中变量的数据类型分为两种,即基本数据类型和引用数据类型。Java中所有的数据类型如图2-4所示。

其中,8种基本数据类型是Java语言内嵌的,在任何操作系统中都具有相同大小和属性,而引用数据类型是在Java程序中由编程人员自己定义的变量类型。本章此处重点介绍的是Java中的基本数据类型,引用数据类型会在以后的章节中做详细的讲解。

  • 整数类型变量

整数类型变量用来存储整数数值,即没有小数部分的值。在Java中,为了给不同大小范围内的整数合理地分配存储空间,整数类型分为4种不同的类型:字节型(byte)、短整型(short)、整型(int)和长整型(long),4种类型所占存储空间的大小以及取值范围。

表列出了4种整数类型变量所占的空间大小和取值范围。其中,占用空间指的是不同类型的变量分别占用的内存大小,如一个int类型的变量会占用4个字节大小的内存空间。取值范围是变量存储的值不能超出的范围,如一个byte类型的变量存储的值必须是-27~27-1之间的整数。

在为一个long类型的变量赋值时需要注意一点,所赋值的后面要加上一个字母L(或小写l),说明赋值为long类型。如果赋的值未超出int型的取值范围,则可以省略字母L(或小写l)。具体示例如下:

long num = 2200000000L; //所赋的值超出了int 型的取值范围,后面必须加上字母L
long num = 198L; //所赋的值未超出int 型的取值范围,后面可以加上字母L
long num = 198; //所赋的值未超出int 型的取值范围,后面可以省略字母L
  • 浮点数类型变量

浮点数类型变量用来存储小数数值。在Java中,浮点数类型分为两种:单精度浮点数(float)和双精度浮点数(double)。double型所表示的浮点数比float型更精确,两种浮点数所占存储空间的大小以及取值范围。

表列出了两种浮点数类型变量所占的空间大小和取值范围,在取值范围中,E表示以10为底的指数,E后面的+号和-号代表正指数和负指数,例如1.4E-45表示1.4*10-45。

在Java中,一个小数会被默认为double类型的值,因此在为一个float类型的变量赋值时需要注意一点,所赋值的后面一定要加上字母F(或者小写f),而为double类型的变量赋值时,可以在所赋值的后面加上字符D(或小写d),也可以不加。具体示例如下:

float f = 123.4f; //为一个float 类型的变量赋值,后面必须加上字母f
double d1 = 100.1; //为一个double 类型的变量赋值,后面可以省略字母d
double d2 = 199.3d; //为一个double 类型的变量赋值,后面可以加上字母d

在程序中也可以为一个浮点数类型变量赋予一个整数数值,例如下面的写法也是可以的。

float f=100; //声明一个float 类型的变量并赋整数值
double d=100; //声明一个double 类型的变量并赋整数值
  • 字符类型变量

字符类型变量用于存储一个单一字符,在Java中用char表示。Java中每个char类型的字符变量都会占用2个字节。在给char类型的变量赋值时,需要用一对英文半角格式的单引号’ ‘把字符括起来,如a’ ‘,也可以将char类型的变量赋值为0~65535范围内的整数,计算机会自动将这些整数转化为所对应的字符,如数值97对应的字符为’a’。下面的两行代码可以实现同样的效果。

char c = 'a'; //为一个char 类型的变量赋值字符'a'
char ch = 97; //为一个char 类型的变量赋值整数97,相当于赋值字符'a'
  • 布尔类型变量

布尔类型变量用来存储布尔值,在Java中用boolean表示,该类型的变量只有两个值,即true和false。具体示例如下:

boolean flag = false; //声明一个boolean 类型的变量,初始值为
falseflag = true; //改变flag 变量的值为true

变量的类型转换

在程序中,当把一种数据类型的值赋给另一种数据类型的变量时,需要进行数据类型转换。根据转换方式的不同,数据类型转换可分为两种:自动类型转换和强制类型转换。

  • 自动类型转换

自动类型转换也叫隐式类型转换,指的是两种数据类型在转换的过程中不需要显式地进行声明。要实现自动类型转换,必须同时满足两个条件,第一是两种数据类型彼此兼容,第二是目标类型的取值范围大于源类型的取值范围。例如:

byte b = 3;
int x = b; //程序把byte 类型的变量b 转换成了int 类型,无须特殊声明

上面的语句中,将byte类型的变量b的值赋给int类型的变量x,由于int类型的取值范围大于byte类型的取值范围,编译器在赋值过程中不会造成数据丢失,所以编译器能够自动完成这种转换,在编译时不报告任何错误。

除了上述示例中演示的情况,还有很多类型之间可以进行自动类型转换,接下来就列出3种可以进行自动类型转换的情况,具体如下:

  1. 整数类型之间可以实现转换,如byte类型的数据可以赋值给short、int、long类型的变量,short、char类型的数据可以赋值给int、long类型的变量,int类型的数据可以赋值给long类型的变量。
  2. 整数类型转换为float类型,如byte、char、short、int类型的数据可以赋值给float类型的变量。
  3. 其他类型转换为double类型,如byte、char、short、int、long、float类型的数据可以赋值给double类型的变量。
  • 强制类型转换

强制类型转换也叫显式类型转换,指的是两种数据类型之间的转换需要进行显式地声明。当两种类型彼此不兼容,或者目标类型取值范围小于源类型时,自动类型转换无法进行,这时就需要进行强制类型转换。

public class Example01 {
    public static void main(String[] args) {
        int num = 4;
        byte b = num;
        System.out.println(b);
    }
}

编译程序报错

出现这样错误的原因是将一个int型的值赋给byte类型的变量b时,int类型的取值范围大于byte类型的取值范围,这样的赋值会导致数值溢出,也就是说一个字节的变量无法存储四个字节的整数值。

在这种情况下,就需要进行强制类型转换,具体格式如下:

目标类型 变量 = (目标类型)值

将例中第4行代码修改为下面的代码:

byte b = (byte) num;

再次编译后,程序不会报错,运行结果如图所示。

需要注意的是,在对变量进行强制类型转换时,会发生取值范围较大的数据类型向取值范围较小的数据类型的转换,如将一个int类型的数转为byte类型,这样做极容易造成数据精度的丢失。

变量的作用域

在前面介绍过变量需要先定义后使用,但这并不意味着在变量定义之后的语句中一定可以使用该变量。变量需要在它的作用范围内才可以被使用,这个作用范围称为变量的作用域。在程序中,变量一定会被定义在某一对大括号中,该大括号所包含的代码区域便是这个变量的作用域。接下来通过一个代码片段来分析变量的作用域,具体如下:

上面的代码中,有两层大括号。其中,外层大括号所标识的代码区域就是变量x的作用域,内层大括号所标识的代码区域就是变量y的作用域。

Java中的运算符

在程序中经常出现一些特殊符号,如+、-、*、=、>等,这些特殊符号称作运算符。运算符用于对数据进行算术运算、赋值和比较等操作。在Java中,运算符可分为算术运算符、赋值运算符、比较运算符、逻辑运算符和位运算符。

算术运算符

算术运算符用在数学表达式中,它们的作用和在数学中的作用一样。下表列出了所有的算术运算符。

表格中的实例假设整数变量A的值为10,变量B的值为20:

操作符描述例子
+加法 - 相加运算符两侧的值A + B 等于 30
减法 - 左操作数减去右操作数A – B 等于 -10
*乘法 - 相乘操作符两侧的值A * B等于200
/除法 - 左操作数除以右操作数B / A等于2
%取余 - 左操作数除以右操作数的余数B%A等于0
++自增: 操作数的值增加1B++ 或 ++B 等于 21
自减: 操作数的值减少1B- - 或 - -B 等于 19

注意

自增(++)自减(- -)运算符是一种特殊的算术运算符,在算术运算符中需要两个操作数来进行运算,而自增自减运算符是一个操作数。

前缀自增自减法(++a, - -a): 先进行自增或者自减运算,再进行表达式运算

int a = 10;
int b = ++a;
最后结果为:a = 10,b = 11;

后缀自增自减法(a++, a- -): 先进行表达式运算,再进行自增或者自减运算

int a = 10;
int b = a++;
最后结果为:a = 10,b = 10;

赋值运算符

下面是Java语言支持的赋值运算符:

操作符描述例子
=简单的赋值运算符,将右操作数的值赋给左侧操作数C = A + B将把A + B得到的值赋给C
+ =加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数C + = A等价于C = C + A
- =减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数C - = A等价于C = C - A
* =乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数C = A等价于C = C A
/ =除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数C / = A等价于C = C / A
(%)=取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数C%= A等价于C = C%A
<< =左移位赋值运算符C << = 2等价于C = C << 2
>> =右移位赋值运算符C >> = 2等价于C = C >> 2
&=按位与赋值运算符C&= 2等价于C = C&2
^ =按位异或赋值操作符C ^ = 2等价于C = C ^ 2
l=按位或赋值操作符C = 2等价于C = C I 2

比较运算符

下表为Java支持的关系运算符

表格中的实例整数变量A的值为10,变量B的值为20:

操作符描述例子
==检查如果两个操作数的值是否相等,如果相等则条件为真(A == B)为假(非真)
!=检查如果两个操作数的值是否相等,如果值不相等则条件为真(A != B) 为真
>检查左操作数的值是否大于右操作数的值,如果是那么条件为真(A> B)非真
<检查左操作数的值是否小于右操作数的值,如果是那么条件为真(A <B)为真
>=检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真(A> = B)为假
<=检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真(A <= B)为真

逻辑运算符

下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假

操作符描述例子
&&称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。(A && B)为假
II称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。(A II B)为真
称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。!(A && B)为真

位运算符

Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。

位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下:

A = 0011 1100
B = 0000 1101
A&b = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011

下表列出了位运算符的基本运算,假设整数变量A的值为60和变量B的值为13:

操作符描述例子
如果相对应位都是1,则结果为1,否则为0(A&B),得到12,即0000 1100
I如果相对应位都是0,则结果为0,否则为1(A I B)得到61,即 0011 1101
^如果相对应位值相同,则结果为0,否则为1(A ^ B)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。(〜A)得到-61,即1100 0011
<<按位左移运算符。左操作数按位左移右操作数指定的位数。A << 2得到240,即 1111 0000
>>按位右移运算符。左操作数按位右移右操作数指定的位数。A >> 2得到15即 1111
>>>按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。A>>>2得到15即0000 1111

运算符的优先级

  • 该表中优先级按照从高到低的顺序书写,也就是优先级为1的优先级最高,优先级14的优先级最低。
  • 结合性是指运算符结合的顺序,通常都是从左到右。从右向左的运算符最典型的就是负号,例如3+-4,则意义为3加-4,符号首先和运算符右侧的内容结合。
  • instanceof作用是判断对象是否为某个类或接口类型,后续有详细介绍。
  • 注意区分正负号和加减号,以及按位与和逻辑与的区别

选择结构语句

if条件语句

if(判断条件) {满足执行}

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        if (a == b) {
            System.out.println("a 和 b 相等");
        }
    }
}

if(判断条件) {满足执行} else {不满足执行}

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        if (a == b) {
            System.out.println("a 和 b 相等");
        } else {
            System.out.println("a 和 b 不相等");
        }
    }
}

if中嵌套if

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 10;
        int c = 20;
        if (a == b) {
            if (b == c) {
                System.out.println("b 和 c 相等");
            } else {
                System.out.println("b 和 c 不相等");
            }
        } else {
            System.out.println("a 和 b 不相等");
        }
    }
}

switch条件语句

switch (表达式){
    case 常量1:
        // 代码块1;
        break;
    case 常量2:
    // 代码块2;
    break;
  default:
    // 代码块n;
    break;
}

关键字说明

  • switch:表示条件表达式,括号里的值是一个规定数据类型的值。
  • case:表示条件分支,case后面跟一个常量,每个case后面的值必须不一样。case的个数可以为0个。
  • default:表示默认分支,default可以省略,通常放在最后。
  • break:表示“停止”,跳出当前switch语句。

switch支持的数据类型

switch()括号中的表达式的结果的类型只能是特定类型,我们将一个double类型的变量放入,发现编译报错:Cannot switch on a value of type double. Only convertible int values, strings or enum variables are permitted。

不难看出这里括号中只支持是int,String,enum型的。
由于java中的类型的自动转型,byte、char、short这三种可以自动转换为int型的类型括号中也支持。
由于java中包装类的自动拆箱,Integer、Byte、Char、Short这四种类型括号中也支持。
总结来说:switch()括号中的表达式支持int、String、enum以及可以自动转型为int的其他类型。

注意

在Java1.6中表达式的类型只能为int和enum,在java1.7后支持了对String的判断,String类型比较特殊。

public class Main {
    public static void main(String[] args) {
        char grade = 'C';
        switch(grade)
        {
            case 'A' :
                System.out.println("优秀");
                break;
            case 'B' :
            case 'C' :
                System.out.println("良好");
                break;
            case 'D' :
                System.out.println("及格");
            case 'F' :
                System.out.println("你需要再努力努力");
                break;
            default :
                System.out.println("未知等级");
        }
        System.out.println("你的等级是 " + grade);
    }
}

执行结果为:

良好
你的等级是 C

说通俗一点就是当前的值,与下面的几个值对比,如果相同的,就执行当前的case,如果找不到对应的值,就执行最后默认的default中的代码。

循环结构语句

while循环语句

  当满足条件时,就循环执行while中的代码块,只要满足,就会被循环执行。

public class Main {
    public static void main(String[] args) {
        int x = 1;
        while (x < 10) {
            System.out.println("x 值为 : " + x);
            x++;
        }
    }
}

执行结果为:

x 值为 : 1
x 值为 : 2
x 值为 : 3
x 值为 : 4
x 值为 : 5
x 值为 : 6
x 值为 : 7
x 值为 : 8
x 值为 : 9

do…while循环语句

首先执行循环体,然后再判断循环条件,如果循环条件不成立,则循环结束,如果循环条件成立,则继续执行循环体。

do{
    循环体;
} while(循环条件);
public class Main {
    public static void main(String[] args) {
        int i = 0;
        do {
            System.out.println("执行第 " + i + "次");
            i++;
        } while (i < 5);
    }
}

执行结果为:

执行第 0次
执行第 1次
执行第 2次
执行第 3次
执行第 4次

for循环语句

当变量满足条件时,就一直循环下去,例子中,i的初始值为0,当满足条件i < 5,就执行循环体中的代码,i++表示没执行一次就增加1

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            System.out.println("执行第 " + i + "次");
        }
    }
}

执行结果为:

执行第 0次
执行第 1次
执行第 2次
执行第 3次
执行第 4次

循环嵌套

嵌套的方式有很多种,这里举例为for中嵌套for,在第一个的条件下,循环第二个for

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < i + 1; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

执行结果为:

*
**
***
****
*****
******
*******
********
*********

跳转语句

break 退出循环

下面的循环跳过了i为3的时候,结束循环。

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            if (i == 3) {
                break;
            }
            System.out.println("当前 i 为:" + i);
        }
    }
}

执行结果为:

当前 i 为:0
当前 i 为:1
当前 i 为:2

continue 跳过当前循环

下面的循环跳过了i为3的时候,继续循环后面的循环体。

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            if (i == 3) {
                continue;
            }
            System.out.println("当前 i 为:" + i);
        }
    }
}

执行结果为:

当前 i 为:0
当前 i 为:1
当前 i 为:2
当前 i 为:4

方法

什么是方法

方法简单的理解就是一段代码块,实现某种功能,也就是能被调用的独立的代码块。下面是基本结构。

访问修饰符 返回值类型 方法名(参数列表){
    方法体
}

访问修饰符

public

用public修饰的类、类属变量及方法,包内及包外的任何类(包括子类和普通类)均可以访问。

protected

用protected修饰的类、类属变量及方法,包内的任何类及包外那些继承了该类的子类才能访问。

default

如果一个类、类属变量及方法没有用任何修饰符,则其访问权限为default(默认访问权限)。默认访问权限的类、类属变量及方法,包内的任何类(包括继承了此类的子类)都可以访问它,而对于包外的任何类都不能访问它(包括包外继承了此类的子类)。default重点突出包。

private

用private修饰的类、类属变量及方法,只有本类可以访问,而包内包外的任何类均不能访问它。

访问修饰符对比

级别修饰符同类同包子类不同包
公开public
受保护protected-
默认不写修饰--
私有private---

返回值类型

Java中的返回值类型,可以是任意一种类型,int,string,Object等,最为特殊的为void,这个类型表示当前方法不返回数据,还有一种为不写返回值类型,这种方法称为构造方法,后面会详细讲解。

方法名

一般习惯命名为一下几种:

  • 包名:com.test.servlet
  • 类名、接口名:UserService
  • 变量名、方法名:userService
  • 常量名:USER_SERVICE

参数列表

一个方法可以不接受参数,接收多个参数,接收可变长度参数列表。

  • 不接受参数:直接方法名()即可
  • 多个参数:方法名(int a, String b, Object c)代表三个参数
  • 可变长度参数列表:表示此处接受的参数为0到多个当前类型的对象,或者是一个当前类型的[],例如:方法名(Object …ob)

分析Main方法

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

public:访问修饰符
static:表示静态方法
void:无返回值
main:方法名
String[] args:参数
System:系统方法
out:标注输入输出
println:方法

方法的重载

重载的特点:

  • 方法名相同
  • 方法的参数类型,参数个不一样
  • 方法的返回类型可以不相同
  • 方法的修饰符可以不相同

下面是例子:

public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        main.Test("汤姆");
        main.Test(20);
    }
    public void Test(String userName) {
        System.out.println("名字为:" + userName);
    }
    public void Test(int userAge) {
        System.out.println("名字为:" + userAge);
    }
}

方法的递归

递归算法是一种直接或间接地调用自身的算法。

最典型的案例为算阶乘,比如说数学计算阶乘为:5!= 5 x 4 x 3 x 2 x 1,下面的例子就是Java实现阶乘,这个思想重要。

public class Main {
    public static void main(String[] args) {
        int num = factor(5);
        System.out.println(num);
    }
    public static int factor(int n) {
        if (n == 1) {
            return 1;
        } else {
            int num = n * factor(n - 1);
            return num;
        }
    }
}

运行结果为:

120

数组

数组的定义

Java 中定义数组的语法有两种:

type arrayName[];  // 例如:String myArray[];
type[] arrayName;  // 例如:String[] myArray;

type 为Java中的任意数据类型,包括基本类型和组合类型,arrayName为数组名,必须是一个合法的标识符,[ ] 指明该变量是一个数组类型变量。

定义带长度的数组,arraySize为长度,其格式如下:

arrayName = new type[arraySize];
// 例如:myArray = new String[10];

通常可以定义时设置长度,语法为:

type arrayName[] = new type[arraySize];
// 例如:String myArray[] = new String[10];

数组的常见操作

import java.util.*;
public class Main {
    public static void main(String[] args) {
        // 初始化数组
        String[] array1 = {"马超", "马云", "关羽", "刘备", "张飞"};
        String[] array2 = new String[]{"黄渤", "张艺兴", "孙红雷", "小猪", "牙哥", "黄磊"};
        // 查看数组的长度
        System.out.println("length:  " + array1.length);
        // 遍历数组
        for (int i = 0; i < array1.length; i++) { 
            System.out.println(array1[i]);
        }
        // 数组 int ---> string
        int[] array3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
        String arrStrings = Arrays.toString(array3);
        System.out.println(arrStrings);
        // 数组中是否包含某一个值
        String a = "马超";
        if (Arrays.asList(array1).contains(a)) {
            System.out.println("马超在这里");
        }
        // 将数组转成set集合
        Set<String> set = new HashSet<>(Arrays.asList(array2));
        System.out.println(set);
        // 将数组转成list集合
        List<String> list = new ArrayList<>();
        for (int i = 0; i < array2.length; i++) {
            list.add(array2[i]);
        }
        String[] arrStrings2 = {"1", "2", "3"};
        List<String> list2 = java.util.Arrays.asList(arrStrings2);
        System.out.println(list2);
        // 数组排序
        int[] arr4 = {3, 7, 2, 1, 9};
        Arrays.sort(arr4);
        for (int i = 0; i < arr4.length; i++) {
            System.out.println(arr4[i]);
        }
        // 从第几个到第几个之间的进行排序
        int[] arr5 = {3, 7, 2, 1, 9, 3, 45, 7, 8, 8, 3, 2, 65, 34, 5};
        Arrays.sort(arr5, 1, 4);
        for (int i = 0; i < arr5.length; i++) {
            System.out.println(arr5[i]);
        }
        // 复制数组
        int[] arr6 = {3, 7, 2, 1};
        int[] arr7 = Arrays.copyOf(arr6, 10);  //指定新数组的长度
        // 只复制从索引[1]到索引[3]之间的元素(不包括索引[3]的元素)
        int[] arr8 = Arrays.copyOfRange(arr6, 1, 3); 
        for (int i = 0; i < arr8.length; i++) {
            System.out.println(arr8[i]);
        }
        // 比较两个数组
        int[] arr9 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
        boolean arr10 = Arrays.equals(arr6, arr9);
        System.out.println(arr10);
        // 去重复
        // 利用set的特性
        int[] arr11 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 2, 4, 5, 6, 7, 4, 32, 2, 1, 1, 4, 6, 3};
        Set<Integer> set2 = new HashSet<>();
        for (int i = 0; i < arr11.length; i++) {
            set2.add(arr11[i]);
        }
        System.out.println(set2);
        int[] arr12 = new int[set2.size()];
        int j = 0;
        for (Integer i : set2) {
            arr12[j++] = i;
        }
        System.out.println(Arrays.toString(arr12));
    }
}
public class Main {
    public static void main(String[] args) {
        int[] arr = {10, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 2, 4, 5, 6, 7, 4, 32, 2, 1, 1, 4, 6, 3};
        // 计算最大值
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        System.out.println("Max is " + max);
        // 计算最小值
        int min = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] < min) {
                min = arr[i];
            }
        }
        System.out.println("Min is " + min);
    }
}

冒泡排序法

public class Main {
    public static void main(String[] args) {
        int[] array = new int[]{5, 3, 6, 2, 10, 2, 1};
        for (int i = 0;i < array.length - 1; i ++) {
            for (int j = i + 1;j < array.length;j ++) {
                if (array[j] < array[i]) {
                    int temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
        }
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
    }
}

运行结果为:

1 2 2 3 5 6 10

选择排序法

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{5, 3, 6, 2, 10, 2, 1};
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                // 如果后一个小于前一个,则把后一个放在最小
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 交换当前索引 i 和最小值索引 minIndex 两处的值
            if (i != minIndex) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
            // 执行完一次循环,当前索引 i 处的值为最小值,直到循环结束即可完成排序
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

运行结果为:

1 2 2 3 5 6 10