跳转至

Java 基础

简介

基本介绍

  • Java 语言难度适中、实用性强。
  • Java 是世界上最流行的编程语言。
  • Java 是一门开放语言。

Hello, World

public class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello World! Go Go Go! 你好,世界!");
    }
}

public class HelloWorld 类——class。HelloWorld 是类名,public class——告诉 Java 类名要与代码文件名一致。大括号内是类的内容。

public static void main(String[] args) —— main 方法的定义,告诉 Java 这事程序入口,也就是程序开始执行的地方。大括号内是方法的内容,又称方法体。main 方法最为特殊的一点是,它是 Java 程序的入口。

System.out.println 是 Java 提供的内置功能,可以将内容输出。小括号里的内容是参数。没有参数的情况下,System.out.println() 会输出一行空行。

注意

  • class 后面的名字是类名。
  • 类名必须与源文件的文件名相同,文件名后缀必须是是小写的 java。
  • main 方法是 Java 程序执行的入口。

数据类型

int

int 用来表示一个整数,取值范围在 -2^31 ~ 2^31-1。计算出来是 -2147483648 ~ 2147483647。

标示符

  • 由大小写英文字符、数字和下划线组成的,区分大小写的,不以数字开头的文字。
  • 可以用作 Java 中的各种东西的名字,比如类名,方法名等。
  • 标示符是区分大小写的。

关键字是 Java 语法的保留字,不能用来做名字。

Java 代码三级跳——表达式、语句和代码块

  • 表达式:Java 中最基本的一个运算。比如一个加法运算表达式。
  • 语句:类似于平时说话时的一句话,由表达式组成,以 ; 结束。
  • 代码块:一对大括号括起来的就是一个代码块。

Java 是区分大小写的

  • 关键字和标示符都是区分大小写的
  • 类名必须与文件名一致,包括大小写要求
  • 使用变量时,名字必须和声明变量时的标示符大小写一致
  • 方法名也区分大小写。main 和 Main 是两个名字
  • 类型也区分大小写。int 是数据类型,Int 则不是
  • System.out.println 可以被 Java 认识,SYSTEM.Out.Println 就不可以

认识进制

十六进制

每一位可以是 0~F 这16个值,到16进位。一百用十六进制表示就是64,十就是 A。

bit 和 byte

  • 一个二进制的位叫做一个 bit。网络带宽中的单位,都是 bit。
  • 八个二进制的位,组成一个 byte。硬盘等存储的单位,都是 byte。
  • byte 是计算机中基本的衡量存储的单位,计算机在对外使用时不会用 bit 作为划分存储的单位。

数字的基本类型

整数类型

  • byte 占用 1 个 byte,值域是 -128~127
  • short 占用 2 个byte,值域是 -32768~32767
  • int 占用 4 个 byte,值域是 -2147483648 ~ 2147483647。Java 中整数缺省的是 int 类型
  • long 占用 8 个 byte,值域是 -9223372036854774808~9223372036854774807

浮点(小数)类型

  • float 占用 4 个 byte,有精度,值域复杂 ±340282346638528859811704183484516925440
  • double 精度是 float 的两倍,占用 8 个 byte。Java 中浮点数缺省是 double 类型。

符号位

布尔和字符数据类型

  • boolean 占用 1 个 byte,值域是 true,false。
  • char 占用 2 个 byte,值域是所有字符。

引用数据类型

  • Java 中的数据类型分为基本数据类型和引用数据类型

引用数据类型和基本数据类型

相同点

  • 都可以用来创建变量,可以赋值和使用其值
  • 本身都是一个地址

不同点

  • 基本数据类型的值,就是地址对应的值。引用数据类型的值还是一个地址,需要通过“二级跳”找到实例。
  • 引用数据类型是 Java 的一种内部类型,是对所有自定义类型和数组引用的统称,并非特指某种类型。

Java 有一个大大的布告板,放着所有实例

Merchandise m1 = new Merchandise();
  • 使用 new 操作符可以创建某个类的一个实例。在 Java 程序运行的时候,所有这些创建出来的实例都被 Java 放在内存里一个叫做堆(heap)的、类似公告板的地方。
  • 创建一个实例,就是根据类的定义,点出需要的“纸”,鼎铛一个本子,挂在布告板上。实例本身,可以认为是一个本子。
  • 引用里存放的,相当于某个本子所在的布告板的地址。

引用的缺省值——null

引用也有缺省值——null:

  • null 是引用类型的缺省值。
  • null 代表空,不存在。可以读作空。
  • 引用类型的数组创建出来,初始值都是空。
  • null 也是 Java 中的关键字。

null 带来的问题:

  • NullPointerException(NPE)
  • 如果不确定,使用前要先判断引用是不是空
  • 访问 null 的任何属性都会报错

运算符

  • 运算符对一个或者多个值进行运算,并得出一个运算结果。
  • 运算符的运算结果类型有的是固定的,有时候会根据被计算的值变化。比如两个 int 相加,结果的类型就是 int。两个 byte 相加,返回值的类型就是 int。
  • 混淆点:除赋值运算外,运算符本身不会更改变量的值。

取模运算符 %

  • 用来计算余数
  • 负数也可以被取模
  • 负数也可以取模
  • 小数也可以取模

比较运算符

  • >
  • >=
  • <
  • <=
  • !=
  • ==

布尔运算符

  • ! 叫做非运算符,not 运算符。
  • & 叫做且运算符,and 运算符。有一个 false 结果就是 false。
  • && 叫做且且运算符,andand 运算符。运算结果和 & 一样。
  • 叫做或运算符,or 运算符。有一个是 true 结果就是 true。
  • || 叫做或或运算符,oror 运算符。运算结果和 一样。

建议用 &&|| ,避免报错。

运算符优先级

  • ()
  • !
  • */%
  • +-
  • >>=<<=
  • ==
  • !=
  • &&&|||
  • =

字面值的八进制和十六进制

  • 以 0 开头的整数为八进制

    05 就是十进制的 5

    011 就是十进制的 9

  • 以 0x 开头的整数的十六进制

    0xF 就是十进制的 15

    0x11就是十进制的 17

按位运算符

  • 按位并(AND):&
  • 按位或(OR):|
  • 按位异或(XOR):^
  • 按位取反:~

用处:掩码(MASK)

位移运算符

  • >>:符号位不动,其余位右移,符号位右边正数补0,负数补1,又称带符号右移。
  • >>>:符号位一起右移,左边补0,又称无符号右移。
  • <<:左移,右边补0.左移没有带符号位一说,因为符号位在最左侧。

用处:高效除以 2

注意:

  • 按位运算符不会改变原本的变量的值。

  • 位移运算符不会改变原本的变量的值。

计算并赋值运算符

作用是为了让代码更简洁。

  • +=
  • -+
  • /=
  • *=
  • %=
  • &=
  • ^=
  • |=
  • <<=
  • >>=
  • >>>=

数据类型自动转换

自动类型转换:

  • 不会出现问题的类型转换,编程语言可以做自动类型转换,比如低精度的数字向高精度的数字转换
  • 自动类型转换可以发生在算术运算,也可以发生在赋值。

数值精度顺序:double > float > long > int > short > byte

char 可以转换为 int:

  • char 可以转换为 int
  • 虽然同样是两个 byte,但是因为 char 是无符号数,值域超出了 short 可以表示的范围,所以不可以自动转为 short。

强制数据类型转换

强制类型转换:

  • 可能出现问题的类型转换,需要使用强制类型转换,比如高精度数值向低精度数值转换
  • 强制类型转换也是操作符
  • 语法是用小括号括起来的目标类型放在被转换的值前面
  • 强制转换会造成数据精度丢失

数值溢出:

  • 数值计算一旦溢出,结果将失去其原有意义。比如,两个正数会加出负数。
  • 要对能够处理的值有大概的估计。

字符集和编码

字符集:

  • 字符集就是字符的集合。一般会包含一种语言的字符。比如 GBK,是包含所有常用汉字的字符集。ASCII 是包含英文字符的字符集。
  • 字符就是 Java 中的 char,char 是 character 的简写。

编码:

  • char 代表一个字符,char 的本质也是数字。将数字映射到字符,就叫编码。
  • 将一个字符集映射到数字,就是给这个字符集编码。编码是有标准的,所有的计算机系统按照同一个编码标准执行。
  • 有时候编码和字符集会混用。

常用的字符集:

  • ASCII 码
  • Unicode 包含世界上所有常用字符,编码也有几种,包括 UTF-8,UTF-16 等。
  • Unicode,GBK 等所有常用的字符集,都会兼容 ASCII。

Java 中的字符集:

  • Java 中有的是 UTF-16 编码的 Unicode。
  • UTF-16 用 16 个 bit,即两个 byte,这也是 char 占用两个 byte 的原因。当把 char 转成数字的时候,需要用 int。

ASCII 码和转义符

如何输出特殊字符:

  • ASCII 码 + char,通过 ASCII 表可以找到需要的字符对应的数字。将这个数字转换为 char,然后输出这个 char。
  • 转义符。转义符用来给字符赋值,也可以用作字符串里面,作为字符串中的一个字符。

转义符语法和常用的转义符:

  • \n:换行号
  • \":双引号
  • \t:制表符
  • \uXXXX:unicode 编码 对应的字符

字符串的“加法”

将变量穿插在字符串中输出:

  • 字符串可以和任何类型进行加法运算,则会将这个值的字符拼接到字符串上。
  • 字符串也可以使用 += 操作符来拼接
  • 字符串的加法运算符符合加法运算符本身的优先级

字符串不是 Java 中的基本数据类型:

  • 字符串的类型的名字叫做 String
  • 虽然 String 不是 Java 中的基础类型,但是也可以使用类似的语法 String stc = "abc" 来创建。开始的时候将其当成基础类型,更容易理解。
  • String 不是 Java 中的保留字。

String 的加法不会改变原 String 变量的值,改变其值要用赋值语句。

自增和自减操作符

  • 自增自减操作符是可以直接改变变量值的操作符
  • 前加加和前减减
  • 后加加和后减减
  • 其实是一个 +1 操作和一个赋值操作的缩写

语句

if-else 语句

  • if-else 语法,只有一个语句块被执行
  • if 和 else 都是 Java 中的关键字
  • 把 if-else 看作一个表达式,程序整体还是顺序执行的
if (boolean ){
    语句块
}else{
    else 语句块
}

if-else 的嵌套

  • if-else 就是一个语句,可以是另一个语句的一部分,也可以是 if-else 的一部分,即嵌套

if-else 的简化

  • 如果 if 或者 else 的语句块只有一个语句,可以省略大括号
if(boolean )
    if 语句块
else
    else 语句块
if(boolean ){
    if 语句块
}else if(){
    if 语句块
}else{
    else 语句块
}

for 语句

  • 让程序在满足某条件时,重复执行某个代码块。for 是 Java 中的关键字
  • 初始语句在 for 循环开始前执行一次,以后不再执行;循环体条件表达式在每次循环体执行前会执行,如果为 true,则执行循环体,否则循环结束;循环体后语句会在每次循环执行后被执行。
for(初始语句;循环体条件表达式;循环体后语句) {
    for 循环体
}

break 语句

  • break 语句可以结束任何循环
  • 不考虑负数的情况,使用 break 改善程序

continue 语句

  • 跳过不符合条件的循环
  • continue 语句可以结束当次循环的执行,开始下一次循环体的执行

代码块

  • 大括号括起来的就是代码块
  • 代码块也叫体,比如 for 循环体,main 方法体
  • 代码块可以嵌套

变量的作用域

  • 代码块里创建和使用变量
  • 代码块里创建变量
  • 不能在外层代码块里使用内层代码块的变量。是否可以使用变量,也称作变量在某个代码块的可见性。也就是说,外层代码块创建的变量对内层代码块可见。内层代码块中创建的变量对外层代码块不可见。
  • 内层命名空间不可以重复定义外层代码块的变量,但是可以使用外层代码块的变量
  • 代码块无论嵌套多少层,都遵循上述变量可见性

作用域和命名空间

  • 同一个命名空间中的变量不可以重名
  • 为了避免变量名冲突,所以必须有命名空间

while 语句

  • 条件表达式的结果是一个 boolean 值,如果为 true,则执行循环体,如果为 false,则循环结束。
  • while 循环体是一个代码块。所以 while 循环也是可以嵌套别的语句的,包括 while 语句,for 语句,if-else 语句等。
while(条件表达式){
    while循环体
}

do-while 语句

  • do-while 语句等循环体至少执行一次
do{
    while循环体
}while(条件表达式);

死循环

  • 无法结束的循环
  • 死循环是因为没有设置好结束条件,循环的结束条件很重要,要充分考虑各种边界情况。

switch 语句

  • 能够根据两个值相比较,进入某个代码块最适合这个情况
switch(用于比较的 int ){
    case 目标值1对应一个 if else(xxx)
        匹配后可以执行的语句
    case 目标值2不可以与别的 case 语句重复:
        匹配后可以执行的语句
    default(对应最后的 else可选);
        default 语句
  • switch 里的 case 子句中也可以有任意合法的语句,比如 if-else,for 循环等。
  • switch 里不同的 case 不能声明相同的变量。
  • switch 语句中用于比较的值,必须是 int 类型。
  • switch 语句适用于有固定多个目标值匹配。然后执行不同逻辑的情况
  • 必须使用 break 语句显示的结束一个 case 语句,否则 switch 语句会从第一个 match 的 case 语句开始执行直到遇到 break 语句或者 switch 语句结束。
  • default 子句是可选的,如果所有的 case 语句都没有匹配上,才会执行 default 中的代码。

Java 中的注释

单行注释

  • //为开始,到这一行结束都是注释内容
  • 注释可以是任何内容
  • 可以在一行的开始注释,也可以在程序内容后面添加注释
  • 注释不会对程序有任何影响

多行注释

  • /* */

生成指定范围内的随机数

  • Math.random() 生成随机数,随机数在 0 到 1 之间,类型是 double。

从标准输出读取字符串和整数

  • Scanner in = new Scanner(System.in) 连接标准输入。in 也是变量,只是不是基本类型。
  • in.nextLine() 可以从命令行读取一行字符串
  • in.nextInt() 可以从命令行读取一个正整数
  • 点操作符也是 Java 中的操作符,和 System.out.println() 以及 Math.random() 中的点是一样的操作符。是对点前面的“变量”进行点后面的“操作”。这里所谓的操作,就是指方法,也就是我们一直写的 main 方法的那个方法。这些操作都是使用一个个的方法。使用方法我们叫做调用方法(invoke a method)/方法是 Java 中的重中之重。
  • import java.util.Scanner; 是告诉程序,Scanner 这个类型在哪里。
  • 创建 Scanner 类型的“变量”,它就是我们提过的工具,可以帮我们从标准收入读取数据
  • nextLine()nextInt() 两个方法可以从命令行读取一行字符串或者一行字符串代表的整数。

数组

  • 数组是相同类型的变量的集合,所有元素的类型都一样
  • 可以指定数组包含的元素个数,最多为 int 的最大值个
  • 元素有固定的顺序
  • 每个元素都有一个固定的编号, 称之为索引,从 0 开始递增,类型为 int
  • 可以像操作变量一样读写数组中的任何一个元素

数组类型

数组是一种特殊的类:

  • 数组的类名就是类型带上中括号
  • 同一类型的数组,每个数组对象的大小可以不一样。也就是每个数组对象占用的内存可以不一样,这点和类的对象不同。
  • 可以用引用指向类型相同大小不同的数组,因为它们属于同一种类型。

引用的数组:

  • 可以把类名当成自定义类型,定义引用的数组,甚至多维数组。

创建和使用一个数组的语法

数组元素类型[]变量名 = new 数组元素类型[数组长度]
变量名[索引]可以使用这个变量可以读取也可以给它赋值

数组的名与实

  • 数组的“实”是一块地址连续的内存,就像是编号连续的一沓白纸。
  • 数组的名,就是这个块连续内存的第一个内存的地址
  • 受伤的变量和基本变量一样,本身是个地址。但是与基本变量不一样的是,这个地址的值,是数组的“名”,也就是数组的第一个地址。

数组=数组变量+数组的实体

  • 数组变量[索引] 就是在数组原有地址的基础上,加上索引,获得想要的元素
  • 所以索引是从 0 开始的,因为数组变量的地址就是数组第一个元素的地址

数组的长度

  • 数组变量 .length 可以获得数组的长度
  • 数组创建之后,长度不可以改变

数组索引过界和初始值

  • 访问数组过界出错的例子,数组出界的错误叫做 IndexOutOfBoundException。
  • 如果没有把握数组是否会出界,可以把索引和数组长度做比较。注意索引是从 0 开始的,不是从 1 开始的。
  • 数组里每个元素都有初始值,初始值和类型有关。对于数字类型,初始值是 0,对于 boolean 类型,初始值是 false。

让变量指向性的数组

  • 数组变量可以指向新的数组实体。这时候,数组变量的值就是新的数组实体的地址了。这种数组变量的赋值操作,叫做让变量指向新的数组。
  • 如果没有别的数组变量指向原来的数组实体,也就是说,如果没有数组变量“记得”原来数组的地址,原来的数组实体就再也不可访问了,也就好像“消失”了。
  • 对于非基本类型的变量,计算机都要通过这种“两级跳”的方式来访问。基本类型变量,一跳就可以。

多维数组

创建一个二维数组,二维数组是一维数组的自然延伸

double[][] 变量名 = new double[][]

Java 是就是使用类来描述世界,用类的实例(对象)让世界运转起来。

如何创建类的实例/对象(Instance/Object)

  • 从数据类型的角度看,类就是自己创建了一种新的数据类型。类也叫做“自定义类型”。一个 Java 程序中不允许类同名。

点操作符

通过点操作符操作对象的属性:

  • 点操作符是用来访问/操作前面实体的属性的,类似于“的”
  • merchandise.name 可以读作 merchandise 的 name

类、对象和引用的关系

类和对象的关系

  • 类是对象的模板,对象是类的一个实例
  • 一个 Java 程序中类名相同的类只能有一个,也就是类型不会重名
  • 一个类可以有很多对象
  • 一个对象只能根据一个类来创建

引用和类以及对象的关系

  • 引用必须是、只能是一个类的引用
  • 引用只能指向其所属的类型的类的对象
  • 相同类型的引用之间可以赋值
  • 只能通过指向一个对象的引用,来操作一个对象,比如访问某个成员变量

像自定义类型一样使用类

类就是一种自定义类型:

  • 在类定义中可以使用类,创建类的引用
  • 在类定义中,甚至可以使用类自己的类创建引用
  • 引用类型的缺省值是 null。一个类定义中如果有引用,创建出来的实例,其缺省值是 null

类的管理

  • 为了避免类在一起混乱,可以把类放在文件夹里。这时就需要使用 package 语句告诉 Java 这个类在哪个 package 里。package 语句要和源文件的目录完全对应,大小写要一致。
  • package 读作包。一般来说,类都会在包里,而不会直接放在根目录
  • 不同的包里可以用相同名字的类
  • 一个类只能有一个 package 语句,如果有 package 语句,则必须是类的第一行有效代码

用 import 使用类

  • 当使用另一个包里的类的时候,需要带上包名
  • 每次使用都带包名很繁琐,可以在使用的类的上面使用 import 语句,一次性解决问题
  • import 语句可以有多个
  • 如果需要 import 一个包中的很多类,可以使用 * 通配符

属性访问修饰符:public

  • 被 public 修饰的属性,可以被任意包中的类访问
  • 没有访问修饰符的属性,称作缺省的访问修饰符,可以被本包内的其他类和自己的对象
  • 访问修饰符是一种限制或者允许属性访问的修饰符

类的全限定名

  • 包名 + 类名 = 类的全限定名。也可以简称为类的全名
  • 同一个 Java 程序中全限定名不可重复

Debug

设置断点,debug 调试模式运行程序。

断点(breakpoint):可以让程序在调试模式停在某一行。

程序调试标准动作:

  • 查看变量的值,展开实例看内部成员变量的值
  • 程序继续执行之 Step Over:执行一行
  • 程序继续执行之 Step Out:继续执行直到遇到下一个断点或者程序结束(执行到方法结束然后返回到调用方法的地方)
  • 指向任意代码之 Evaluate Expression:在对话框输入代码,直接执行看结果值
  • 条件断点:给断点设置条件,只有满足条件时,程序才会在该断点停住
  • Resume Program:执行到程序结束

方法

方法英文名叫做 method,又称作 function。

方法的调用:

  • 通过引用的点操作符,可以调用对象的方法
  • 方法调用要有括号,即使没有参数
  • 不能用类来调用方法

方法可以使用的数据:对象的成员变量(member variable)

方法体内部定义的变量叫做局部变量。

参数和返回值的传递

  • 方法里使用的参数相当于一个局部变量。只是在方法调用之前,会用实参给参数的形参赋值。
  • 发生在代码块里的,就让它留在代码块里。方法执行完毕,参数和方法的局部变量的数据就会被删除回收。
  • 调用一个有返回值的方法时,就好像访问一个成员变量。
  • 参数本身可以是一个表达式,只要表达式的值类型可以和参数类型匹配。
  • 对于引用类型,参数同样是一个表达式。
  • 方法里的代码不能改变实参的值。
  • 给返回值赋值,并不会影响用来充当返回值的变量。

名词解释

  1. 缺省值,default 值,默认值三个词是一个意思。代表某种数值类型的默认值。

参考资料

  1. 课程平台:极客时间,课程链接:https://time.geekbang.org/course/intro/100027801
回到页面顶部