写点什么

Java 基本概念详解

  • 2022 年 7 月 13 日
  • 本文字数:7762 字

    阅读完需:约 25 分钟

注释

在 Java 中,注释有三种,分别为:


  • /** 这是一种多行注释,它是 Java 所特有的注释方式。使用该种注释方式,可以使得 JDK 的工具 javadoc 可以提取出该注释中的内容,构成该源代码文件的说明书。 javadoc 命令的使用方法为: javadoc 源程序文件名 */

  • /* 这也是一种多行注释,它的功能同 C 中的一样,它同第一种注释的区别在于,这种注释中的内容是 javadoc 不会提取该注释中的内容 */

  • // 这是一种单行注释,它只能用于一行的行尾,它的功能同 C 中的也是一样的,同样它的注释内容也不能由 javadoc 提取

  • 注意: 注释是不能嵌套使用的

标识符

  • 标识符是某种语法成分的 名字 ,如类名、变量名、方法名等;

  • 标识符是没有长度限制的 Java letters 和 Java digits 的序列,第一个必须是 Java letter,标识符不能和关键字, boolean 常量和 null 常量一样。

  • Java letters 包括 ASCII 拉丁字母 A–Z, 和 a–z, 还包括 ASCII 下划线 (_) 和美元符号 ( 通常是用于机器自动产生的代码中;

  • Java digits 包括 ASCII 数字字符 0-9。

  • 标识符区分大小写

  • 在定义标识符时,最好见名知义

标识符命名规范

  • 类名、接口名

  • 类名应该是英文名词,尽量见名知义,如果类名由多个单词构成,每个单词的首字母大写,如:ImageSprite;

  • 包名

  • 所有都用小写字母

  • 变量名、对象名、方法名等标识符首单词字母全小写,其他单词首字母大写,也要尽量见名知义

  • 方法名应该是动词,如:getBackground();

  • 变量名,除了临时变量以外,避免使用单字母名字,如:float myWidth;

  • 常量名

  • 常量名全部用大写,单词之间用“_”隔开,如:int MIN_WIDTH=4;

  • 成员变量

  • static 成员变量名以 s 开始

  • 非 public、非 static 成员变量名以 m 开始

  • 其它以小写字母开始

  • 如:


  public class MyClass {      public static final int SOME_CONSTANT = 42;      public int publicField;      private static MyClass sSingleton;      int mPackagePrivate;      private int mPrivate;      protected int mProtected;  }
复制代码


  • 对于简称,最好也把它当作单词来用,如下表:

  • <table><tr><td>建议</td><td>不建议</td></tr><tr><td>XmlHttpRequest</td><td>XMLHTTPRequest</td></tr><tr><td>getCustomerId</td><td>getCustomerID</td></tr><tr><td>Html</td><td>HTML</td></tr><tr><td>url</td><td>URL</td></tr><tr><td>id</td><td>ID</td></tr></table>

  • 示例:

  • 合法标识符

  • String、i3、MAX_VALUE、isLetterOrD、_123Test、HelloWorld、public1

  • main 也为合法标识符,但是我们建议只把它作为类的执行入口方法的名字,不做其他使用

  • 不合法标识符

  • 123Test、Hello-World、HelloWorld#、public、Hello World

关键字

关键字是 Java 系统所定义有特定语法含义的字符序列,如:class、public 等等,关键字不能作为标识符使用。


  • 下列字符序列作为关键字:

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

  • boolean 常量 true 和 false,以及 null 常量也应该看作关键字。

类型

我们在学习一门计算机语言的时候,一定要了解这个语言支持哪些数据类型。Java 语言是强类型(strongly typed)语言,这意味着在 Java 中,所有的数据,包括常量、变量和表达式都会有一个类型。


Java 语言的类型分为两类:基本类型(primitive types)和引用类型(reference types):


  • 基本类型包括数字类型以及布尔类型 boolean,数字类型包括:

  • 整数类型(integral types):byte, short,int, long, 和 char;

  • 浮点类型(floating-point types):float 和 double。

  • 引用类型有 class 类型、interface 类型、array 类型,以及枚举类型。


每种基本类型均有相应的封装类与之对应,这些封装类封装了对应的基本类型的相关操作,如下表:


基本类型

基本类型同其他面向过程的语言的类型类似,对于这种类型,我们所关注的是这些类型的类型名,相应类型数据的取值范围,数值的取值范围是同该种类型的数据在内存中所占大小密切相关的。下面来看看各基本类型在内存中的占用情况。


  • 整数类型 integral types 有 byte, short, int, 以及 long, 他们的值分别为 8-bit,16-bit, 32-bit 和 64-bit 有符号(signed)补码整数,char 类型的值为 16-bit 无符号(unsigned) 整数,它的值为 Unicode 字符编码。由此,它们的取值范围如下:

  • byte -2^7~2^7-1

  • short -2^15~2^15-1

  • int -2^31~2^31-1

  • long -2^63~2^63-1

  • char '\u0000'~'\uffff'

  • 浮点类型 floating-point types 有 float 和 double ,它们的值分别为 32-bit 和 64-bit 的 IEEE 754 浮点数。

  • boolean 类型有两个值 true 和 false,不讨论它的大小

字面量(literal)

所谓字面量是那种一看就知道其值的常量,比如:1.23、"abc"、true、'a'等。因为在 java 中所有的数据都有类型,那么字面常量也有其类型,每种类型的字面常量也有其特定的写法。literal 常量的类型有:基本类型、 String 类型的值,包括 null。


  • 整数常量(integer literal)有三种表示形式,十进制表示(decimal (base 10)), 十六进制(hexadecimal (base 16)), 或八进制(octal (base 8))

  • 一个十进制数是 0 到 9 的序列(第一个不能是 0,因为 0 是八进制数的起始数字),表示正整数;

  • 一个十六进制数由 0x 或 0X 开头,后跟若干位十六进制补码数字,因为补码数的特点,十六进制数码本身是包含符号的,因此十六进制数字可以表示正数、负数和 0;

  • 一个八进制数以 0 开头,后跟若干八进制数,表示正数、负数和 0,道理同上;

  • 在 java7 以后允许二进制表示,以 0b 或 0B 开头,后跟 0、1 的组合

  • 在 java7 以后数字间还可以加_作为数字分隔,如:0xffff_ffff、0377_7777_7777

  • 整数后跟 L 或 l ,建议使用 L(小写 l 在视觉上同数字 1 不好区分,当然,计算机是可以明白无误区分的),表示该数的类型为 long 类型,若无后缀,则为 int 类型。

  • 浮点常量 floating-point literal 可以有以下部分:whole-number(整数) part, a decimal point (小数点), a fractional part(小数部分), an exponent(指数部分),和一个类型后缀

  • 如果为十进制表示,则在整数部分或者小数部分至少有一位数字,同时,小数点、指数、类型后缀这三者至少出现一个。其它部分可选。指数部分由 e 或 E 后跟可带符号的整数;

  • 如果为十六进制表示,以 0x 或 0X 开头,则在整数部分或者小数部分至少有一位数字,必须有指数部分,指数部分由 p 或 P 后跟可带符号的整数;类型后缀可选。

  • 浮点数后跟 F 或 f ,则其类型为 float,若无后缀,则其类型为 double, 即是后缀 D 或 d 可选。

  • float 常量的例子:

  • 1e1f 2.f .3f 0f 3.14f 6.022137e+23f

  • double 常量的例子:

  • 1e1 2. .3 0.0 3.14 1e-9d 1e137

  • boolean 常量

  • boolean 有两个值 true 和 false。

  • 字符常量

  • character literal 是单引号(single quotes)括起来的字符

  • 下面为 char 常量(三种形式)

  • 第一种形式(单引号中为需表达的字符)

  • 'a'

  • '%'

  • 第二种形式(单引号中为转义的字符)

  • '\t'

  • '\ '

  • '''

  • 第三种形式(以十六进制或者八进制表示的的字符)

  • '\u03a9'

  • '\uFFFF'

  • '\177'

  • 转义(Escape)序列:

  • \b /* \u0008: 退格 backspace BS */

  • \t /* \u0009: horizontal tab HT */

  • \n /* \u000a: linefeed LF 使得打印机走纸到下一行*/

  • \f /* \u000c: form feed FF 使得打印机走纸到下一页*/

  • \r /* \u000d: carriage return CR 使得打印头回到行首*/

  • " /* \u0022: 双引号 double quote" */

  • ' /* \u0027: 单引号 single quote ' */

  • \ /* \u005c: 反斜线 backslash \ */

  • \OctalDigit

  • \OctalDigit OctalDigit

  • \ZeroToThree OctalDigit OctalDigit

  • native2ascii 的使用:该命令为 JDk 中所提供的工具,可以通过该命令查看某个字符的 unicode 编码。如图:

  • 字符串常量(string literal)由双引号括起来的零个(含)以上的字符序列。

  • 每个字符都可能由转义序列(escape sequence)组成。

  • 字符串的类型为 String(String 为一种 java 类名,它表示字符串),两个值相同的字符串常量其实是类 String 的同一实例。

  • 字符串例子:

  • "" // 空字符串

  • """ // 只包含 " 的字符串

  • "This is a string" // 一个包含 16 个字符的字符串

  • "This is a " + "two-line string" /* 由两个字符串连接成的字符串常量 */

  • null 是个常量值,但这个常量值没有具体的类型,它可以成为任何引用类型的值

变量

顾名思义,变量就是其值可以改变的量,但在 java 中并不是所有的变量值都是可以改变的。变量是计算机内存中的一块存储区域,这块区域有名字类型作用域,通过变量名使用变量中的数据,变量的类型决定该变量可取值和可进行的运算与操作。


  • 变量必须定义,通过定义,可以知道变量的名字及其类型,其定义形式如下:type variablename

  • 根据其类型来分类,可分为两种

  • 基本类型的变量中存放该变量的值

  • 引用类型的变量中存放该变量值的引用(实际就是地址),注意不是变量值,变量值本身为对象,在堆中存放,变量中存放该对象在堆中的地址,我们称为引用。

  • 在 java 中,变量定义的位置有四种,这四种位置决定了变量的作用域(Scope),变量作用域就是变量名字起作用的范围,有四类作用域,如图所示:

  • 成员变量(member variable),是类或对象的组成部分,表示对象的属性,它在类的方法或构造方法(constructor)之外定义。成员变量的作用域充满整个类。如果对成员变量的使用如果是在某个初始化语句之中,该成员变量的定义必须出现在该语句之前。如下例:


    public class Test {//本例没有任何问题      int j = f(); //定义一个成员变量j,并进行初始化
int f(){ int j;//这里的j是局部变量j,不是上面所定义的成员变量j j = i; return j; } int i=9; }
public class Test { int j = f(i);//虽然i这个成员变量的作用域在这里是有效的,但这里无法使用i,会出现“非法前向引用”错误 int i = 9;
int f(int x){ int j; j = x; return j; } }
复制代码


- 局部变量(local variable),在一块代码内定义的变量称为局部变量(local variables),这种变量的作用域从其定义位置开始到它所在的块结束为止。如下程序段:
复制代码


    {int x=90;      { int x=80;}    }//不允许:局部变量不允许再次定义    {int x=90;        { int y=80;}    }//可以
复制代码


- 方法参数(method parameter),这种变量类似局部变量,用来给方法或构造器传值,它的作用域在它所在的方法体中。- catch异常参数(exception handler parameter),它的作用域在它所在的catch块中。
复制代码

示例 1

/*  关于变量的作用域:有效范围。作用范围。    出了大括号就不认识了。*/public class VarTest03{ //类体      //声明变量  int m = 100;    public void m1(){    int m = 200;//该m不是上面所定义的m,这个m为局部于m1方法中的局部变量    System.out.println(m); //200   }    public static void m(){//这里的m为方法名,它不同于变量,可以同变量同名        int k = 10;  }      public static void main(String[] args){        int i = 10;    System.out.println(i);        //Error    //无法访问m方法中的k变量.    //System.out.println(k);        //for循环    /*    for(int j = 0; j < 10; j++){      System.out.println(j);    }        //Error,j变量是属于for循环的。    System.out.println(j);    */        //j的作用域从此开始直至main方法结束,这里的j同上面for中的j不同。    int j;        for(j = 0; j < 10; j++){      System.out.println(j);    }        System.out.println(j);
}}
复制代码

变量初始化(Variable Initialization)与使用

  • 在定义局部变量和成员变量时可以用赋值语句进行初始化。如:


  int i=1;  
复制代码


  • 在相同作用域里不能定义同名的局部变量

  • 成员变量的名字可以和成员方法的名字同名

  • 局部变量没有初始化,不可使用;成员变量没有初始化,则系统自动初始化(0,null,false),所以成员变量定义后,未显式初始化,也可使用

final variable

可以把某个变量定义为值不可改变的变量,这种 final 变量的值一旦得到第一个值以后就不能再改变了。它的定义方式为在变量定义前加上关键字 final,如:


final int aFinalVar = 0; 
复制代码


上面的语句定义了一个 final 变量,并且同时初始化了它,之后再改变它的值,就会出现编译错。


如果需要,可以推迟 final 局部变量的初始化(注意是局部变量),如:


final int blankfinal; . . . blankfinal = 0; 
复制代码


一个 final 局部变量定义了但是没有初始化,称为:blank final。

表达式(Expressions)

expression 就是一系列操作数及运算符连接起来的式子,单独一个常量、变量、方法也均可以看作一个表达式,所以说一个普通的表达式可以看作由子表达式组合而成。


表达式有两方面含义:执行计算和返回结果。有一类表达式为常量表达式,在编译时就计算值,如:


true(short)(1*2*3*4*5*6)Integer.MAX_VALUE / 22.0 * Math.PI"The integer " + Long.MAX_VALUE + " is mighty big."
复制代码


表达式运算结果的值和类型依赖于运算符和操作数的类型。表达式的计算顺序依赖于运算符的优先级,优先级( Precedence )是指运算符计算的优先顺序。除了‘=’, ‘==’ 和 ‘!=’可用于对象以外,其它所有的运算符只支持简单类型。另外, String 类支持 ‘+’ 和 ‘+=’,表示字符串的连接运算;

Java 运算符(Operators)

Java 运算符的分类

根据运算符所能够进行运算的操作数的个数,我们可以把运算符分为:一元运算符、二元运算符、三元运算符。通常一元运算符的优先级最高,三元运算符的优先级最低,二元运算符的优先级处于中间。


根据运算符的功能我们大致可分为赋值运算符、算术运算符、逻辑运算符、关系运算符、位运算符及其他运算符等。


有些运算符会改变它的操作数的值,比如所有的赋值运算,自增自减运算等,这种现象称为副作用。

赋值运算(Assignment)

赋值运算符为‘=’,它可以同其他的二元运算符组合为复合赋值运算,这一点同 C 相似。


赋值号左边必须变量,赋值号右边可以是一般意义上的表达式,它的含义是将赋值号右边的表达式的计算结果放在赋值号左边的变量中存储起来。因为赋值也是运算,所以说赋值运算也有运算结果,它的结果同赋值号左边变量中的值一致,这一点很重要。比如:a = 3 ,这个赋值运算表达式的值为 3。


另外,大家考虑 a = b = c = 3 这个表达式的计算意义,它的计算过程不是:3 放入 c,再把 c 的值放入 b,b 的值再放入 a,而应该考虑作 a = (b = (c = 3))),即是,b 中的值是(c = 3)这个子表达式的值,而不是 c 的值。


对于基本类型的赋值,为值的复制,如: a = b;把 b 的值复制到 a,a、b 中所保存的为相等值的两个不同副本,在该赋值运算之后,如果修改 a 的值不会影响到 b,同理,修改 b 的值,也不会影响到 a 的值。


如果赋值号右边为引用类型的结果,我们可以类比 C 语言中的指针。例如:如果 a,b 是引用类型的变量,那么 a = b ,实际上 a 和 b 引用的是同一个对象。如果我们改变 a 或者 b 的值,这时 a 和 b 就不再引用相同的对象了。但是如果我们通过 a 或者 b 改变的是它们所引用对象中的值,因为 a、b 引用的是同一个对象,所以不管通过 a 还是 b 来观察这个对象,所看到的结果都是一致的。比如,我们把 a、b 看作两个男生,如果 b 把自己暗恋的女生介绍给 a 认识,结果 a 也暗恋上了该女生,那么 a、b 就暗恋同一个女生,那么如果 b 送给女生一本《Java 语言程序设计基础》,a、b 是不是同时都知道该女生有了这本书。但是如果 b 移情别恋了,a、b 就不再有相同的暗恋对象,不管 a、b 给自己的暗恋女生送什么,对对方都没有影响。如下例:


class Girl{ //女生类,女生都有一本书《计算引论》  String book = "计算引论";}
class Boy{ //男生类,每位男生默认情况下没有女朋友 Girl girlFriend = null;}
public class Test{ public static void main(String[] args){ //两位女生 Girl g1 = new Girl(); Girl g2 = new Girl();
//两位男生 Boy b1 = new Boy(); Boy b2 = new Boy();
//b1暗恋g1 b1.girlFriend = g1;
//b1把自己的暗恋女生介绍给了b2,b2也暗恋上了g1,他们的暗恋对象都是g1 b2.girlFriend = b1.girlFriend;
//b1送给g1女生一本《Java语言程序设计基础》 b1.girlFirend.book = "Java语言程序设计基础"; //通过b2来看,b2暗恋的女生也有一本《Java语言程序设计基础》, //奇怪吗?不奇怪,本来就是同一位女生 System.out.println(b2.girlFriend.book);
//b1移情别恋g2 b1.girlFriend = g2;
//b1的暗恋女生有什么书呢? System.out.println(b1.girlFriend.book);
//痴情的b2的暗恋女生有什么书呢? System.out.println(b2.girlFriend.book);
}}
复制代码


关于复合赋值,它的一般形式为: a Y= b,这里 Y 代表某种二元运算符,它的等价形式为 a = a Y (b),这里 b 的左右一定要有小括号,为什么呢?我们考虑这个表达式: a *= b + 2,我们知道该表达式的含义为先计算 b + 2,然后将该值乘以 a,最后结果放在 a 变量中,如果它的等价形式中没有小括号,是不是等价形式就成为: a = a * b + 2,还同原来的表达式含义一致吗?

算术运算符(Mathematical operators)

关系运算符(Relational operators)

关系运算的结果为 boolean 值,均为二元运算。六个关系运算符为 小于(<), 大于(>), 小于等于 (<=), 大于等于 (>=), 等于 (==) 和 不等于 (!=),它们均为二元运算符。其中, == 和 != 的操作数可以是 boolean,其它关系运算符的操作数不可以是 boolean。== 和 != 对于引用是比较两个引用是否为同一对象(那两个男生的暗恋对象是不是一个女生),而不是比较对象是否包含相同内容;在用于比较浮点数时,由于浮点数在计算机中的表示是不精确的,所以我们看起来一样的值,可能计算机比较的结果是不同的,尤其要小心。因此,我们在比较浮点数的相等或不等的时候,我们通常是用一个精确范围来进行比较,而不用==与!=来进行比较,用数学的写法即是 |a - b| < Δ ,这里Δ是一个充分小的一个正数,只要 a、b 的差值落在Δ范围内即认为是相等的。

逻辑运算符(Logical operators)

与 (&&), 或 (||) and 非 (!) 的操作数是逻辑值,结果依赖于参数的逻辑关系。非为一元运算,其它两个为二元运算。


在进行逻辑运算的时候,如果某个时刻能够得到整个表达式的值时,则计算到此为之,其余部分的表达式不再计算,这种现象称为短路。比如:(a >b) && (c++ > d) && (e >f),如果 a > b 的值已经是 false,后面的(c++ > d)和(e > f)均不再计算了,但是,结合运算符的副作用,你就会发现,根据 a、b 之间的大小关系,该表达式计算完成以后,c 的值可能增 1,也可能不增 1,这种情况,大家要小心。


位运算操作符(Bitwise operators)

按位与 (&),按位或 (|),按位异或 (^),按位非 (~),对操作数的每一位进行运算。按位非为一元运算,其它为二元运算。


按位与、或、异或可以和 = 组合使用: &=, |= 和 ^= (因为 ~ 是一元操作,所以不能和 = 组合使用)。


boolean 类型值可以进行按位与、或、异或,但不能执行执行按位非。


对于 boolean 进行按位运算不会发生短路。


发布于: 2022 年 07 月 13 日阅读数: 29
用户头像

InfoQ签约作者 2020.11.10 加入

文章首发于公众号:五分钟学大数据。大数据领域原创技术号,深入大数据技术

评论

发布
暂无评论
Java基本概念详解_Java_五分钟学大数据_InfoQ写作社区