Java语法掌握:打好编程基础的关键

命名规范

代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
正例:name / sex / age

反例:*name / _sex / $age

代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。

正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式
也要避免采用。

正例:alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文。

反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3

类名使用 UpperCamelCase风格。

但以下情形例外:BO/DTO/VO/AO/PO/UID等。

正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion

反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion

方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
正例: localValue / getHttpMessage / inputUserId

反例:local_value / localvalue

常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例:UNIVERSITY_OF_CODE

反例:UNI_OF_CODE

抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。
正例:BaseService / NameEmptyException / UserServiceTest

类型与中括号紧挨相连来表示数组。
正例:定义整形数组 int[] arrayDemo;

反例:在 main 参数中,使用 String args[]来定义。

POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。
正例:success

反例:is_success

包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。
正例:应用工具类包名为 com.alibaba.ai.util、类名为 MessageUtils(此规则参考 Spring 的框架结构)

杜绝完全不规范的缩写,避免望文不知义。
正例:BaseService / NameEmptyException / UserServiceTest

反例:BaseS / NEException / USTest

注释

行内注释

// 单行注释

多行注释

/*
    这是多行注释
*/

类注释

类注释必须放在 import 语句之后,类定义之前。

标记由 @开始, 如 @author或 @param。

package test;
import java.util.Random;

/**
 * @author XUEW
 */
public class RandomTest {

}

方法注释

每一个方法注释必须放在所描述的方法之前。

/**
 * 这是hello方法
 * @param name 名字
 * @return 打招呼
 */
public String hello(String name) {
    return "Hello" + name;
}

标记

类注释和方法注释上均可以使用标记进行文档的详细描述,之后方便生成 Java Doc。

通用标记:既可以声明在类注释,也可以声明在方法注释。
标记描述
@author作者,这个标记将产生一个 author(作者)条目。可以使用多个 @author 标记,每个标记对应一个作者。
@version版本,这个标记将产生一个 version(版本)条目。这里的文本可以是对当前版本的任何描述。
@since始于,这个标记将产生一个 since(始于)条目。这里的 text 可以是对引入特性的版本描述。例如:@since version 1.7.10
@deprecated过时,这个标记将对类、方法或变量添加一个不再使用的注释。文本中给出了取代的建议。
@see超链接,这个标记将在 see 后面部分增加一个超级链接。它可以用于类中,也可以用于方法中。例如:@see world.xuewei.entity.Employee#raiseSalary(double)
@date创建日期,例如:@date 2022-01-01 12:30
方法标记:声明在方法注释上
标记描述
@param变量描述,这个标记将对当前方法的 param(参数)部分添加一个条目。这个描述可以占据多行,并可以使用 HTML标记。一个方法的所有 @param标记必须放在一起。
@return返回,这个标记将对当前方法添加 return(返回)部分。这个描述可以跨越多行,并可以使用 HTML 标记。
@throws异常,这个标记将添加一个注释,用于表示这个方法有可能抛出异常。

基本数据类型

Java 是一种强类型语言,定义一个变量就需要声明一个类型。

Java有一个能够表示任意精度的算术包,通常称为“大数值”(big number)。虽然被称为大数值,但它并不是一种新的 Java 类型,而是一个 Java 对象。

1个字节(Byte)= 8 比特位(Bit)

4 种整型

由于 Java 程序必须保证在所有机器上都能够得到相同的运行结果, 所以各种数据类型的取值范围必须固定。

在通常情况下,int 类型最常用。但如果表示星球上的居住人数,就需要使用 long 类型了。byte 和 short类型主要用于特定的应用场合,例如,底层的文件处理或者需要控制占用存储空间量的大数组。

长整型数值有一个后缀L或l,如4000000000L。

2 种浮点型

除了 float 和 double,还有三个特殊的浮点数值,用来表示溢出和出错的情况。

  1. 正无穷大 Double.POSITIVE_INFINITY
  2. 负无穷大 Double.NEGATIVE_INFINITY
  3. NaN(不是一个数字)Double.NaN

例如:正数 / 0 = 正无穷大,0 / 0 = NaN

判断数字是否为无穷大小 d.isInfinite()

判断数字是否为数字 d.isNaN()

绝大部分应用程序都采用 double 类型,但是浮点数值不适用于无法接受舍入误差的金融计算中。2.0 - 1.1 = 0.89999999999…,这种舍入误差原因是浮点数系统使用二进制来表示,但是二进制系统无法精确的表示分数。比如三分之一就没法用二进制表示。

1 种字符型

**char 类型的字面量值要用单引号括起来,只需要 1 个字节。**例如:‘A’ 是编码值为 65 所对应的字符常量。它与 "A"不同,"A"是包含一个字符 A 的字符串。

char 类型的值可以表示为十六进制值。其范围从 \u0000 到 \uffff,特殊字符的转义序列如下。

注意:当心注释中的\u片段,可能会报语法错误

比如下面的注释就会报错

public static void main(String[] args) {
  // 目标地址 c:\user\home
  System.out.println("Hello World");
}

1 种真值型

boolean(布尔)类型有两个值:false 和 true,用来判定逻辑条件。

关于布尔类型的存储字节数,网上大概有三种说法:

1个比特
理由是 boolean 类型的值只有 true 和 false 两种逻辑值,在编译后会使用 1 和 0 来表示,这两个数在内存中只需要 1 位(bit)即可存储,位是计算机最小的存储单位,八分之一个字节。

1个字节
理由是虽然编译后 1 和 0 只需占用 1 位空间,但计算机处理数据的最小单位是 1 个字节,1 个字节等于 8 位,实际存储的空间是:用 1 个字节的最低位存储,其他 7 位用 0 填补,如果值是 true 的话则存储的二进制为:0000 0001,如果是 false 的话则存储的二进制为:0000 0000。

4个字节
理由来源是《Java虚拟机规范》一书中的描述:“虽然定义了 boolean 这种数据类型,但是只对它提供了非常有限的支持。在 Java 虚拟机中没有任何供 boolean 值专用的字节码指令,Java 语言表达式所操作的 boolean 值,在编译之后都使用 Java 虚拟机中的 int 数据类型来代替,而 boolean 数组将会被编码成 Java 虚拟机的 byte 数组,每个元素 boolean 元素占 8 位”。这样我们可以得出 boolean 类型单独使用是 4 个字节,在数组中又是 1 个字节

变量转换

隐式转换

两个数值进行二元操作时(例如 n + f,n 是整数,f 是浮点数),先要将两个操作数转换为同一种类型,然后再进行计算。

  • 如果两个操作数中有一个是 double 类型,另一个操作数就会转换为 double 类型。
  • 如果其中一个操作数是 float 类型,另一个操作数将会转换为 float 类型。
  • 如果其中一个操作数是 long 类型,另一个操作数将会转换为 long 类型。
  • 否则,两个操作数都将被转换为 int 类型。

强制转换

在必要的时候,int 类型的值将会自动地转换为 double 类型。但另一方面,有时也需要将 double 转换成 int。在 Java 中,允许进行这种数值之间的类型转换。

当然,有可能会丢失一些信息。在这种情况下,需要通过强制类型转换(cast)实现这个操作。

强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。

double x = 9.997;
int nx = (int)x;

上面这种情况会丢失精度,所以注意不要将大范围类型的数据转为小范围类型的数据。

字符串

从概念上讲,Java 字符串就是 Unicode字符序列。 例如, 串 Java\u2122 由 5 个Unicode 字符 Java

Java 没有内置的字符串类型, 而是在标准 Java 类库中提供了一个预定义类,很自然地叫做 String。

每个用双引号括起来的字符串都是 String 类的一个实例:

String e = ""; // an empty string
String greeting = "Hello";

代码单元和码点

每一个字符通常被称为代码单元(code unit),char 类型描述了 UTF-16 编码中的一个代码单元。

码点(code point)是指与一个编码表中的某个字符对应的代码值。在 Unicode 标准中,码点采用十六进制书写,并加上前缀 U+,例如 U+0041 就是拉丁字母 A 的码点。

字符串的拼接和截取

字符串可以直接使用 + 进行拼接,但是这种方式效率较低,后面会介绍 StringBuilder。

当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串。

如果需要把多个字符串放在一起,用一个定界符分隔,可以使用静态join方法:String s = String.join("*", "1", "2", "3");

字符串的截取操作可以调用substring方法。

不可变字符串

底层使用的是 final char[] 用来存储每个字符,并且 String 类没有提供用于修改字符串的方法。

private final char value[];

String 类被 final 修饰,表示这个类不可以被继承,意味着创建一个 String 的时候,创建完成后字符串本身的长度和内容就固定了,不能二次修改。此时在内存中指向了一块内存地址,当二次赋值的时候,并不是在原有基础上修改,而是重新指定一块新的内存地址原始地址的数据将会被 JVM 的自动垃圾回收机制回收

比较相等使用 equals 方法

s.equal(t)

如果字符串 s 与字符串 t 相等,则返回 true;否则,返回 false。

检测两个字符串是否相等,而不区分大小写,可以使用 equalsIgnoreCase 方法。

一定不要使用 == 运算符检测两个字符串是否相等!这个运算符只能够确定两个字串是否放置在同一个内存位置上。

常量池

String str1="abc";
String str2="abc";
String str3=new String("abc");
String str4=new String("abc");
String str5=str4.intern();

str1==str2 //第一行,true
str1==str3 //第二行,false
str1==str5 //第三行,true
str3==str4 //第四行,false
str3==str5 //第五行,false

str1.equals(str2) //第六行,true
str1.equals(str3) //第七行,true
str1.equals(str5) //第八行,true
str3.equals(str4) //第九行,true
str3.equals(str5) //第十行,true

第一行:str1 和 str2 在赋值时,使用的是字符串常量。**Java 虚拟机有一个常量池机制,它会直接把字符串常量放入常量池中,从而实现复用。**因此 str1 和 str2 指向的是常量池中的同一个内存地址,所以返回值是 true。

第二行:str3 是用 new 关键字创建的,在 Java 中,new 关键字代表创建一个新对象。因此 str3 指向的是一个全新的内存地址。而 str1 指向的是一个常量池中的旧地址,因此 str1 和 str3 肯定是不同的,所以返回值是 false。

第三行:str5 是用 String 类的 intern() 方法创建的。JDK 文档中对 intern 方法是这样描述的:“返回一个常量池中的固定对象。当 intern 方法被调用时,如果常量池中已经包含了这个 String 对象(用 equals 方法判断包含与否),那么直接返回这个对象。否则,就向常量中添加这个对象,并返回对它的引用”。

第四行:str3 和 str4 使用 new 关键字分别创建了新的对象,所以返回值是 false。

第五行:str3 是指向新创建的内存地址,而 str5 指向常量池中的对象地址,两者是不可能相等的,因此返回值是 false。

对于第六、七、八、九、十行,它们全部使用 eqauls() 方法进行比较。关于 String 类的equals方法,JDK文档是这样说的:“equals 方法返回 true 当且仅当它的入参不为空并且它们代表相同的字符串内容”

空串和Null串

空串"" 是长度为 0 的字符串。空串是一个 Java 对象,有自己的串长度( 0 ) 和内容(空)。
if (str.length() = 0) 或 if (str.equals (""))

String 变量还可以存放一个特殊的值,名为 null,这表示目前没有任何对象与该变量关联。
if (str = = null )

String 类常用基础API

StringBuilder

使用 + 进行字符串拼接的时候效率很低,每次连接字符串都会创建一个新的 String 对象,即耗时又浪费空间。使用 StringBuilder 类就可以避免这个问题的发生。

首先创建一个空的字符串构造器,然后不断的调用 append 方法,当构建完成的时候调用 toString() 得到 String 对象类型的字符串结果。

StringBuilder builder = new StringBuilder();
builder.append("str");
...
String result = builder.toString();

注意,StringBuilder并不是线程安全的,但是效率高,它的前身是StringBuffer,它才是线程安全的,但是效率较低。这两个类的API都是相同的。

输入和输出

键盘读取输入

Scanner

要想通过控制台进行输人,首先需要构造一个 Scanner 对象,并与“标准输入流” System.in 关联。

Scanner in = new Scanner(System.in);

Console

因为输入是可见的,所以 Scanner 类不适用于从控制台读取密码。 Java SE 6 特别引入了 Console 类实现这个目的。要想读取一个密码, 可以采用下列代码:

Console cons = System.console();
String username = cons.readLine("User name: ");
char[] passwd = cons.readPassword("Password: ");

为了安全起见,返回的密码存放在一维字符数组中, 而不是字符串中。

输出

System.out.print( )

普通输出

System.out.println( )

换行输出

System.out.printf( )

格式化输出

System.out.printf("Hello, %s. Next year, you'll be %d" , name, age) ;

每一个以 %字符开始的格式说明符都用相应的参数替换。格式说明符尾部的转换符将指示被格式化的数值类型:f 表示浮点数,s 表示字符串,d 表示十进制整数。

流程控制

块作用域

块(即复合语句)是指由一对大括号括起来的若干条简单的 Java 语句。块确定了变量的作用域。一个块可以嵌套在另一个块中。不能在嵌套的两个块中声明同名的变量。

条件控制
if (age >= 0 && age < 1) {
  System.out.println("婴儿");
} else if (age >= 1 && age < 5) {
  System.out.println("幼儿");
} else if (age >= 5 && age < 11) {
  System.out.println("儿童");
} else if (age >= 11 && age < 18) {
  System.out.println("少年");
} else if (age >= 18 && age < 35) {
  System.out.println("青年");
} else if (age >= 35 && age < 60) {
  System.out.println("中年");
} else {
  System.out.println("老年");
}
循环控制

在循环中可以使用 break 跳出循环,continue 跳过本次循环。

for 循环

for 循环语句是支持迭代的一种通用结构,利用每次迭代之后更新的计数器或类似的变量来控制迭代次数。

在循环中,检测两个浮点数是否相等需要格外小心。由于舍入的误差, 最终可能得不到精确值,无法达成终止条件。

for (int i = 0; i < 10; i++) {
  // 注意这里是从 0 开始的,0~9
	System.out.println("第" + i + "次循环");
}
for each 循环

JDK 5 引入增强 for 循环,for each 循环语句的循环变量将会遍历数组中的每个元素,而不需要使用下标值。

int[] array = new int[]{1, 2, 3, 4, 5};
for (int num : array) {
  System.out.println(num);
}
while 循环

while 循环语句首先检测循环条件。因此,循环体中的代码有可能不被执行。

int i = 0;
while (i < 10) {
  // 循环内容
  System.out.println(i);
  // 更新循环条件
  i++;
}
do/while 循环

至少执行一次

int i = 10;
do {
  // 循环内容
  System.out.println(i);

  // 更新循环条件
  i++;
}
while (i < 10);
多重选择:switch 语句

在处理多个选项时,使用 if/else 结构显得有些笨拙。

switch 语句将从与选项值相匹配的 case 标签处开始执行直到遇到 break 语句,或者执行到 switch 语句的结束处为止。如果没有相匹配的 case 标签,而有 default 子句,就执行这个子句。

case 标签可以是:

  • 类型为 char、 byte、 short 或 int 的常量表达式。
  • 枚举常量。
  • 从 Java SE 7 开始,case 标签还可以是字符串字面量

**有可能触发多个 case 分支。如果在 case 分支语句的末尾没 break 语句,那么就会接着执行下一个 case 分支语句。**这种情况相当危险,常常会引发错误。

int i = 3;
switch (i) {
  case 1:
    System.out.println("这是1");
    break;
  case 2:
    System.out.println("这是2");
    break;
  case 3:
    System.out.println("这是3");
    break;
  default:
    System.out.println("这是默认");
    break;
}

大数值

如果基本的整数和浮点数精度不能够满足需求,那么可以使用 java.math 包中的两个很有用的类:Biglnteger 和 BigDecimal。这两个类可以处理包含任意长度数字序列的数值。Biglnteger 类实现了任意精度的整数运算,BigDecimal 实现了任意精度的浮点数运算。

注意的是,不能使用+ - * / 来处理运算,而是需要使用它们提供的API。

Biglnteger

BigDecimal

使用 BigDecimal 的 divide 方法进行除法运算的时候,需要指定小数位的取舍方式( rounding mode )。

RoundingMode.HALF_UP 是在学校中学习的四舍五入方式。它适用于常规的计算。

默认保留一位小数,如果想指定保留小数位,可以参考下面

BigDecimal value = d2.divide(d1, 2, RoundingMode.HALF_UP);

提供的其他的取舍方式还有:

方式描述
RoundingMode.UP向远离 0 的方向舍入。保留两位小数为例: 1.371 -> 1.38 -1.371 -> -1.38
RoundingMode.DOWN向靠近 0 的方向舍入。保留两位小数为例: 1.371 -> 1.37 -1.371 -> -1.37
RoundingMode.CEILING全向右靠,向大靠拢。保留两位小数为例: 1.371 -> 1.38 -1.371 -> -1.37
RoundingMode.FLOOR跟 CEILING 相反,全向左靠,向小靠拢。保留两位小数为例: 1.371 -> 1.37 -1.371 -> -1.38
RoundingMode.HALF_UP四舍五入。保留两位小数为例: 1.375 -> 1.38 -1.371 -> -1.37
RoundingMode.HALF_DOWN五舍六入。保留两位小数为例: 1.375 -> 1.37 1.376 -> 1.38
RoundingMode.HALF_EVEN-
RoundingMode.UNNECESSARY-

数组

数组是一种数据结构,用来存储同一类型值的集合。**通过一个整型下标可以访问数组中的每一个值。**例如,如果 a 是一个整型数组,a[i] 就是数组中下标为 i 的整数。

int[] a = new int[100];

创建了一个可以存储 100 个整数的数组。索引从 0-99,试图访问元素 a[100](或任何在 0~99之外的下标),程序就会引发 “array index out of bounds” 数组下标越界异常而终止执行。

要想获得数组中的元素个数,可以使用 array.length

有个更加简单的方式打印数组中的所有值,即利用 Arrays 类的 toString 方法。调用 Arrays.toString(a) 返回一个包含数组元素的字符串,这些元素被放置在括号内,并用逗号分隔,例如,“[2,3,5,7,11,13]”

声明数组有两种方式,int[] aint a[],但是推荐使用第一种!

  • 数字数组,所有元素都初始化为 0
  • boolean数组的元素会初始化为false
  • 对象数组的元素则初始化为一个特殊值null,这表示这些元素未存放任何对象。

数组的初始化以及匿名数组

int[] array = { 2 , 3, 5 , 7, 11, 13 }; 
int[] array = new int[] { 17, 19, 23, 29, 31, 37 }

在 Java 中,允许数组长度为 0。

数组的复制

在 Java 中,允许将一个数组变量拷贝给另一个数组变量。这时,两个变量将引用同一个数组。

int[] array1 = {1,2,3,4,5}
int[] array2 = array1

array2[0] = -1

由于两个引用指向了同一个变量,那么 array1[0] 的值也就发生的变化。

如果想实现完全的复制出单独一份数组的话,需要使用 Arrays.copyOf 方法:

int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);

第 2 个参数是新数组的长度。这个方法通常用来增加数组的大小。

数组的排序

要想对数值型数组进行排序,可以使用 Arrays 类中的 sort 方法,这个方法使用了优化的快速排序算法

int[] a = new int[10000];
Arrays.sort(a);

多维数组

double[][] balances = new double[5][5];

int[][] magicSquare =
{
{1, 2, 3, 4},
{1, 2, 3, 4, 5, 6},
{1, 2, 3, 4, 5, 6, 7},
{1, 2, 3, 4},
}

一但数组被初始化,就可以利用两个方括号访问每个元素,例如,balances[i][j]。

Java 还可以方便地构造一个“不规则“数组,即数组的每一行有不同的长度。

常用API

笔记大部分摘录自《Java核心技术卷I》,含有少数本人修改补充痕迹。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值