我们需要了解一些基础的Java 语法来进行java的学习,这里我做了一些小小的总结,具体涉及以下内容:标识符和关键字,数据类型(基本数据类型、基本数据类型的转换、引用数据类型),常量和变量,运算符,语句,方法。这部分是Java后续的基石,可以这么理解:标识符和关键字用来给接下来的各种内容起名字,数据类型用于给变量和常量设置类型,变量需要进行运算有各种运算符,这些运算可以归结为语句,循环或者判断,而语句放在方法里执行,这样我们一个整体语法基石就构建完成了。
是通过看视频,看书了解的,现在拿出来与大家分享,这部分的学习大概从2015年10月开始。首发于CSDN,于2021年1月21日二次更新和补充。
标识符和关键字
标识符和关键字就是我们在Java代码中填写的一些命名,只不过标识符是我们自己能定义的,关键字则有其特殊含义。
标识符
标识符就是一切可以起名字的地方:包名、类名、接口名、方法名,常量名、变量名等,标识符有以下的命名规则
- 标识符由字母、数字、
_
(下划线)、$
符 组成 - 不能以数字开头
- 不允许单独使用下划线作为分隔符(Java9)
- 不能用Java中的保留字(关键字)
- 对大小写敏感,长度没有限制
标识符采用有意义的简单命名,一般我们用一个英文单词去命名,并且遵循如下命名规范(驼峰命名法):
- 包名:包名一般采用全小写的格式
- 类名和接口名:每个单词的首字母大写,其余为小写。(大驼峰即帕斯卡命名法)
- 方法名和变量名:第二个单词起的首字母为大写,其余全为小写。(小驼峰)
- 常量名:基本数据类型的常量名使用全部大写字母,字与字之间用下划线分隔。
以上就是一些简单的标识符命名规范。
关键字
什么是关键字呢?关键字就是在java语言中赋予特殊含义的单词,它有两个特点:1.组成的关键字的单词全是小写,2.常见的代码编辑器中,对关键字都有特殊的颜色标记,共计48个关键字:
- 用于包的关键字[2]:import(导入这个类所存在的包);package(定义包的关键字,将有关类放在一个包中)
- 定义类、接口、抽象类[3]:class(声明一个类);interface(声明一个接口);abstract(表明类或者成员方法具有抽象属性)
- 用于建立类与类之间关系[2]:implements(implements 表明一个类实现了给定的接口类);extends (表明一个类型是另一个类型的子类型,常见的类型有类和接口)
- 用于定义访问权限修饰符[4],Java分别定义了四种访问级别:private、protected(当前包不一定为子类以及跨包子类均可)、default(默认访问限制)、public
- 用于定义建立实例及引用实例、判断实例[4]:new(用来创建新的实例对象),this(指向当前实例对象的引用),super(表明当前对象的父类型的引用或者父类型的构造方法),instanceof(用来测试一个对象是否是指定类型的实例对象)
- 用于定义类、函数、变量修饰符【4】:final(终结器,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量); static(表示具有静态属性);synchronized(线程同步,修饰一段代码表示多个线程都能同步执行) ,volatile (原子操作,表明两个或者多个变量必须同步地发生变化),native(本地用来声明一个方法是由计算机相关语言实现的(如C/C++语言等))
- 用于异常处理【5】:try(尝试一个可能抛出异常的程序块);catch(用在异常处理中,用来捕捉异常);finally(用于异常处理情况,用来声明一个基本肯定会被执行到的语句块(有没有异常都执行));throw(通常用在方法体中,并且抛出一个异常对象,程序在执行到throw语句时立即停止,它后面的语句都不执行);throws(如果一个方法可以引发异常,本身不对异常进行处理,将异常抛给调用者使程序可以继续执行下去)
- 程序控制语句【11】:break(跳出循环); continue (继续);return (返回);do (运行);while(循环);if (如果);else(反之);for (循环);switch (开关);case (返回开关里的结果); default (返回默认结果)
- 数据类型关键字【11】:boolean(布尔型);byte( 字节型);char (字符型);double (双精度);float( 浮点);int (整型);long (长整型);short (短整型);string(字符串);enum(枚举类型);strictfp(strict float point 精确浮点)。
- 用于特殊用途【2】:assert (断言,用来进行程序调试); transient(表示一个成员变量不是该对象序列化的一部分)
除了48个关键字之外,还有2个保留关键字
- 保留关键字【2】:goto(跳转到)、const(常量)。(现在没用以后可能用到作为关键字)
剩下的都是保留字,Java保留字是指现有Java版本尚未使用,但以后版本可能会作为关键字使用:
- 特殊直接量【3】:true(正确);false(错误);null(空值)
- 其它保留字【9】: byValue, cast,future, generic, inner,operator, outer, rest, var
也就是说,Java中48个关键字、2个保留关键字以及12个保留字,都不能作为标识符来使用,这点需要注意,其中除了9个其它关键字,以上关键字与保留关键字以及特殊直接量会编译错误,而9个其它关键字不会,但仍然不建议使用,防止以后作为关键字使用导致的历史代码无法正确运行。
java的关键字与保留字
还有要注意true,false,null,不是java的关键字,但是你不能把它们作为java标识符用。
标识符和关键字了解后可以看一个简单示例:
Java数据类型
在上文保留字中我们提到了Java涉及的一些数据类型,这些类型在常量和变量中的定义中也会用到,我们先来梳理下:
Java 语言是一种强类型语言。通俗点说,在 Java 中存储的数据都是有类型的,而且必须在编译时就确定其类型。 Java 中有两类数据类型:
- 基本数据类型变量:存的是数据本身,基本数据类型变量里存储的是直接放在抽屉里的东西
- 引用类型变量:存的是保存数据的空间地址,引用数据类型变量里存储的是这个抽屉的钥匙,钥匙和抽屉一一对应
需要注意的是String 是一种常见的引用数据类型,用来表示字符串。
基本数据类型
我们知道基本数据类型有8种,name接下来对基本数据类型涉及内容及转换过程做详细介绍。
基本数据类型特性
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。Java中所有的数据类型在所有的操作系统上占的位数都一样,所以可以跨平台。 各个基本类型如下所示:
- byte【1字节】:byte 数据类型是8位、有符号的,以二进制补码表示的整数;最小值是 -128(-2^7);最大值是 127(2^7-1);默认值是 0;byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;例子:byte a = 100,byte b = -50。
- short【2字节】:short 数据类型是 16 位、有符号的以二进制补码表示的整数最小值是 -32768(-2^15);最大值是 32767(2^15 - 1);Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;默认值是 0;例子:short s = 1000,short r = -20000。
- int【4字节】:int 数据类型是32位、有符号的以二进制补码表示的整数;最小值是 -2,147,483,648(-2^31);最大值是 2,147,483,647(2^31 - 1);一般地整型变量默认为 int 类型;默认值是 0 ;例子:int a = 100000, int b = -200000。
- long【8字节】:long 数据类型是 64 位、有符号的以二进制补码表示的整数;最小值是
-9,223,372,036,854,775,808(-2^63)
;最大值是9,223,372,036,854,775,807(2^63 -1)
;这种类型主要使用在需要比较大整数的系统上;默认值是 0L;例子: long a = 100000L,Long b = -200000L。"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。 - float【4字节】:float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;float 在储存大型浮点数组的时候可节省内存空间;默认值是 0.0f;浮点数不能用来表示精确的值,如货币;例子:float f1 = 234.5f。
- double【8字节】:double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;浮点数的默认类型为double类型;double类型同样不能表示精确的值,如货币;默认值是 0.0d;例子:double d1 = 123.4。
- boolean【1字节】:boolean数据类型表示一位的信息;只有两个取值:true 和 false;这种类型只作为一种标志来记录 true/false 情况;默认值是 false;例子:boolean one = true。
- char【2字节】:char类型是一个单一的 16 位 Unicode 字符;最小值是 \u0000(即为 0);最大值是 \uffff(即为65、535);char 数据类型可以储存任何字符;例子:char letter = ‘A’;。
了解了8大基本数据类型和注意事项后我们再看看它们是怎么相互转换的。
基本数据类型转换
基本数据类型之间满足以下条件可以实现互相转换:
- 布尔类型和其他类型不可以互相转换
- byte,short,char不能互相转换,在做运算之前会自动转换为int类型。
- 容量小的类型可以自动转换为容量大的数据类型【byte,short,char—》int—》long—》float—》double】
- 特殊情况: Java语言整型默认为int型,声明long型常量时候需要后边加’L’或者‘l’,
long l=1232323L
,当赋值给long变量没有加‘ l ’或‘ L ’ ,仍旧默认成int类型。如果赋值的时候没有超出int表述范围没关系,即使超出了int的表述范围,也不用担心,不会报错但会导致数值计算错误
- 特殊情况: Java语言整型默认为int型,声明long型常量时候需要后边加’L’或者‘l’,
- 容量大的转换为容量小的需要强制转化,可能会丢失精度,特殊情况:
- 赋值的时候只要int类型的数没有超出(byte,short,char)的表述范围,可以直接byte a=23,
- Java语言默认浮点型常量为double型,如果要声明一个常量float型,则需要在后边加f或者F, 直接转不过去,直接转会导致溢出现象,
float l=1232323.45F
- 多种混合计算时,自动将所有数据类型转换为容量最大的一种数据类型。
以下为一些转换的代码示例:
public static void main(String[] args) {
boolean b=true;
System.out.println(b);
byte b1=67; //byte类型直接后边赋值即可,int类型可以自动赋值到byte上,只要不超过127,但是float f=0.1就不行,必须加f,虽然没超出范围。总结起来就是整型之间虽然不是int但是只要没超过int范围就没必要加强制转换或者是末尾加l,但是浮点型的不行,一定得加强制转换或者是末尾加f。
byte b2=99;
byte b3= (byte)(b1+b2); //在计算之前(byte,short,char会自动转换为int,所以需要强制转换为byte)
System.out.println(b3); //如果直接超过127 ,不会有溢出错误,直接砍掉多余位数
char c1='t';
int b4=b3+c1;
System.out.println(b4); //char,byte,short不可以互相转,但是可以进行混合运算
int i1=123;
int i2=456;
double d1=(i1+i2)*1.2; //系统将会自动把int型的转为double型的计算,因为浮点型的1.2是默认double型的,混合运算中又要取最大范围
System.out.println(d1);
float f1=(float)d1; //因为d1是double型的,所以要强制转换为float型的。
System.out.println(f1);
double d2=1e200;
float f2=(float)d2;
System.out.println(f2); //因为d2超出了float能承受的范围,所以会溢出
float f3=12.344343f; //后边必须加f
long l1=1234l;
long l2=3455l;
float f4=f3+l1+l2;
System.out.println(f4); //混合运算自动都变为float型的
long l3=(long)f4;
System.out.println(l3); //强行把浮点数类型的转化为整型的会导致没有小数位,不是四舍五入,而是彻底没有小数部分。
}
转换过程预期和纠错:
public static void main(String[] args) {
int i=1,j=12; //对i,j赋初始值
float f1=(float)0.1; //0.1f与这里的写法是有区别的,0.1f表示内存分配就分配了4个字节,而这种写法意思是8字节的double类型然后强制转换
float f2=123; //123默认是int类型的,可以自动转为float
long l1 = 12345678,l2=8888888888L; //l1这里没有超出int的范围,所以不用加l,而l2显然超过啦,所以必须加l
double d1 = 2e20,d2=124; //int类型自动转为double
byte b1 = 1,b2 = 2,b3 = 127; //只要没超过int的表述范围,赋值不需要加强制转化
j = j+10;
i = i/10;
i=(int)(i*0.1); //这里虽然与上边相同的计算结果,过程不一样,首先计算后为double,必须加强制转化
System.out.println(i); //i是int型,10是int型,所以计算结果为0,也必须是int型
i = (int)(i*0.1); //i是int型的,乘0.1后变为double型,必须强制转化为int型
char c1='a',c2=125;
byte b = (byte)(b1-b2);
char c = (char)(c1+c2-1); //混合运算,统统转为int,运算结束后再转为char型的
float f3 = f1+f2;
float f4 = (float)(f1+f2*0.1);
double d = d1*i+j;
float f = (float)(d1*5+d2);
}
引用数据类型
除了基本数据类型,都是引用类型,一般包含包含类、接口和数组,其实String类型也可以当作一种引用类型。引用类型占两块内存:一块为空值,定义一个引用类型;另一块为引用类型new出来的放堆里边进行动态内存分配,不用的时候就会被垃圾回收机制回收。
- 栈内存:存放堆内存中的真实对象地址
- 堆内存:存放new出来的动态对象,不用的时候就会被垃圾回收机制回收
关于引用类型如何使用在后边的blog会提到,关于Java的内存结构也会在后边提到,这里做简单记忆。
常量和变量
了解了数据类型和语法后,我们先来了解下Java里的常量和变量分别指什么。
变量
变量指的是值会改变的量,在Java中我们通过三个元素来描述变量:变量类型,变量名以及变量值。按照不同的角度,变量可以做如下的分类:
- 局部变量和成员变量:局部变量表示在方法体里面声明的变量,成员变量表示类体里面,方法体外边声明的变量,注意方法的参数属于局部变量,成员变量会默认初始化,而局部变量不会。成员变量并不能随意在各个方法中使用,如果想直接使用,成员变量与方法之前必须加static关键字,此时该成员变量或成员方法即相当于全局的概念,如果不加static,那么必须先new该类出一个实例,然后再调用变量和方法
- 按照方法的作用域划分:凡是在大括号里声明的变量,出了大括号就没人认识它了,在这个大括号里边的都认识它。
- 按照数据类型划分变量,不同的变量类型来划分。
变量还有一些特征和使用规范:
- Java 中的变量需要先声明后使用,变量使用时,可以声明变量的同时进行初始化,也可以先声明后赋值
- 命名规范:虽然语法中没有提示错误,但在实际开发中,变量名不建议使用中文,容易产生安全隐患,譬如后期跨平台操作时出现乱码等等
- 赋值规范:变量中每次只能赋一个值,但可以修改多次,main 方法中定义的变量必须先赋值,然后才能输出
以上就是变量的分类和使用规范了。
public class testvar {
//int j;
static int j; // 成员变量,可以作用于整个类
public void m() { // 虽然在main方法里也有i,但没关系,作用域都是本方法
int i = 0;
System.out.println(i);
}
public static void main(String[] args) {
int i=0 ;
int t=i+5; //这里局部变量i必须先被赋初始值,否则不能编译。
int k=j+5; //成员变量可以不用赋初始值,系统会默认分配
System.out.println(k);
//testvar tt=new testvar(); //非静态方法,需要先new出一个对象来,然后再调用
System.out.println(i);
//System.out.println(tt.j);
System.out.println(j); //只有成员变量定义为static,才可以直接打印
System.out.println("tianmaolin" + 123); // 这个属于常量的概念,直接可以打印相对应的常量值,不用定义声明赋值。
boolean b = false;
if (b) {
int c = 0;
System.out.println("b is true");
}
// System.out.println(c); //打印不出来,出了c的作用域了,根本就找不到c
long longNum1 = 8888888888888L;
常量
所谓常量可以理解成一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变,常见常量类型有如下几种:
- 整形常量:int ,long
- 浮点型常量:float,double
- 字符常量(char):‘a’
- 字符串常量(string):“abcdefg”
- 逻辑常量(boolean):布尔类型,true ,false
常量还可以表示值不可以改变的变量,例如final关键字:final 常量名=值:final double PI=3.14。常量名一般使用大写字符。程序中使用常量可以提高代码的可维护性。例如,在项目开发时,我们需要指定用户的性别,此时可以定义一个常量 SEX,赋值为 “男”,在需要指定用户性别的地方直接调用此常量即可,避免了由于用户的不规范赋值导致程序出错的情况
运算符
按照运算符分类,Java支持如下的运算符类别:算数运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、字符串连接运算符。
- 算数运算符【7】:算术运算符包括通常的加(+)、减(-)、乘(*)、除(/)、取模(%),完成整数型和浮点型数据的算术运算;Java允许对浮点数进行取模操作。例如,3%2 的结果是 1, 15.2%5 的结果是 0.2。取模操作还可以用于负数,结果的符号与第一个操作数的符号相同,例如,5%-3 的结果是 2;算术运算符还有 自增(++)、自减(–)两种,分别称为加1和减1运算符。这两种运算符有前缀形式和后缀形式,含义有所不同。例如,i++ 和 ++i 的执行顺序是不一样的,i++ 在 i 使用之后再 +1,++i 在 i 使用之前先 +1。i-- 和 --i 的情况于此类似;2,-5%3 的结果是-2
- 位运算符【7】:位运算符用来对二进制位进行操作,包括按位取反(~)、按位与(&)、按位或(|)、异或(^)【相同为0相异为1】、右移(>>)、左移(<<)和无符号右移(>>>)。位运算符只能对整数型和字符型数据进行操作
- 关系运算符【7】:关系运算符用来比较两个值,包括大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、等于(==)和不等于(!=)、instaceof(检查是否是类的对象)。关系运算符都是二元运算符,也就是每个运算符都带有两个操作数,运算的结果是一个逻辑值。Java允许“==”和“!=”两种运算符用于任何数据类型。例如,既可以判断两个数的值是否相等,也可以判断对象或数组的实例是否相等。判断实例时比较的是两个对象在内存中的引用地址是否相等
- 逻辑运算符【5】:逻辑运算符包括逻辑与(&)、逻辑与【短路版】(&&)、逻辑或(|)、逻辑或【短路版】(||)和逻辑非(!)。前两个是二元运算符,后一个是一元运算符。Java对逻辑与和逻辑或提供“短路”功能,也就是在进行运算时,先计算运算符左侧的表达式的值,如果使用该值能得到整个表达式的值,则跳过运算符右侧表达式的计算,否则计算运算符右侧表达式,并得到整个表达式的值
- 条件运算符【1】:也称为 “三元运算符”或“三目运算符”。语法形式( ? : ):布尔表达式 ? 表达式1 :表达式2。运算过程:如果布尔表达式的值为 true ,则返回 表达式1的值,否则返回 表达式2 的值。
- 赋值运算符【12】:赋值运算符的作用就是将常量、变量或表达式的值赋给某一个变量,,赋值符号 " = " 可以和算术运算符结合成复合赋值运算符,例如
= += -= *= /= %= &= |= ^= ~= <<= >>= >>>=
- 字符串连接运算符【1】:主要用来将和字符串连接的内容转为字符串**(+)**
以上这些运算符的优先级排序如下:
括号级别最高,逗号级别最低,单目 > 算术 > 位移 > 关系 > 逻辑 > 三目 > 赋值
语句
语句分为条件语句以及循环语句,接下来分别举例说明。
条件语句
条件语句有两种,if+else和switch:
public static void main(String[] args) {
int i = 7;
if (i < 20) {
System.out.println("free");
} else if (i < 40) {
System.out.println("normal:100yuan");
} else if (i < 60) {
System.out.println("free");
} else {
System.out.println("ok,you are right");
}
}
switch语句如下所示:
public class choose {
public static void main(String[] args) {
int i = 7;
switch (i) { //java中的switch只能探测int型的数据
case 3:
System.out.println(33);
break; //每个break必须要打,如果没有,就会发生case穿透问题,直接连同下一个case内容都打印出来
case 4:
case 7:
case 12: //多个case可以合并到一起,是或的关系
System.out.println(44);
break;
case 5:
System.out.println(55);
break;
default: //default可以省略,但最好不要省略,破坏了程序的健壮性
System.out.println("error");
break;
}
}
循环语句
循环语句分为for循环语句、while语句以及do-while语句:
- for循环语句,一般有固定的循环次数
- while和do-while循环语句,一般没有固定的执行次数,其中while先判断再执行,do-while则先执行再判断
- 循环终止语句break和continue: break表示跳出,continue表示终止本次循环
以下为一个循环代码的示例:
public static void main(String[] args) {
int result = 0;
for (int i = 1; i <= 99; i += 2) {
result += i;
}
System.out.println(result);
int x = 0;
while (x < 10) {
System.out.println(x);
x++;
} //while....是先判断条件然后执行语句
x = 0;
do { //do...while是先执行一次再判断条件
x++;
System.out.println(x);
} while (x < 10); //注意后边的分号!!
int stop=4;
for(int i=1;i<=10;i++){
if(i==stop) break; //注意if语句后边不要加分号!!!!
System.out.println("i="+i); //终止整个语句块儿的循环,跳出循环语句
}
int skip=3;
for(int i=1;i<=10;i++){
if(i==skip) continue; //终止本次值的循环,直接跳到下一次
System.out.println("i="+i);
}
System.out.println(fabonacciloop(-3)); //用循环的方式解决斐波那契数列问题
}
分支+循环解决斐波那契数列问题:
public static long fabonacciloop(int index) {
if (index<1) {
System.out.println("erro");
return -1;
}
if (index == 1 || index == 2) {
return 1;
} else {
long f1 = 1L;
long f2 = 1L;
long f = 0L;
for (int i = 3; i <= index; i++) {
f = f1 + f2;
f1 = f2;
f2 = f; //循环,变量互换赋值
}
return f;
}
}
更多的测试代码如下:
public static void main(String[] args) { //每隔5个为一行打印出100内能被3整除的数
int num = 0;
for (int i = 0; i < 100; i++) { //0~100之内能被3整除的数
if (i % 3 == 0) {
System.out.println(i);
num++;
}
if(num==5){
break; //如果计数达到5个可以被3整除,则终止计数
}
}
public class testloop { //打印出100--200之间所有的质数
for (int i = 101; i < 200; i+=2) {
boolean f=true;
for (int j = 2; j < i; j++) {
if (i%j==0) {
f=false; //如果不是质数,设f为false,然后终止本次循环
break; //注意,这里只是把内层循环终止了
}
}
if(!f){ //如果不是质数,执行跳过,没跳过的都是质数,打印出来
continue;
}
System.out.println(i);
}
}
方法
方法表示一段特定功能的代码,包含:形参、实参、返回值、返回值类型、方法名。
public class testmethod {
public static void main(String[] args) { //主车间,进行组装的地方
m();
m2(2); //这里传入的4, 相当于实参,实际传入的参数
m3('3', 4);
m4(4, 6); //有返回值,但是并没有被打印出来
/*int i = m4(4, 6);
System.out.println(i);*/ //把该返回值传给i,然后打印出该返回值
}
public static void m() { //该分车间不返回任何值,只是顺序执行
//return; //直接return会报错,因为没有任何语句得到执行
System.out.println("ok");
System.out.println("hello");
}
public static void m2(int i) { //形式参数i,必须传入一个值且必须为int类型的
if(i > 3)
return;
System.out.println(i);
}
public static void m3(int i, int j) { //该分车间可以有两个
System.out.println(i + j);
}
public static int m4(int i, int j) { //该分车间具有返回值
return i > j ? i : j;
}