入门
环境
classpath
classpath
是 JVM 用到的一个环境变量, 用来指示 JVM
到何处去搜索 class
在 Windows 系统中, 不同目录间用 ;
分隔, 带空格的目录使用
""
包裹
例: 1
.;C:\work\project1\bin;C:\shared;"D:\jiafeimiao\project1\bin"
需要注意的是当前目录使用 .
代表, JVM 的按照
classpath
中的路径顺序查找, 如果在某个路径下找到了对应的
class
文件就不再继续搜索, 如果所有路径都没找到, 即报错.
基本框架
Java 程序的基本单位是 class
, class
是关键字.
在 class
内部, 可以定义若干方法 (method).
1 | public class Hello{ |
注释
与 C/C++ 基本一致, 但是多了一种文档注释
1 | /** |
基本数据类型
类型名 | 意义 | 存储空间 | 取值 |
---|---|---|---|
boolean | 布尔类型 | 未规定 | true 和
false (默认) |
byte | 字节类型 | 1 Byte | -127 ~ 127 默认值是0 |
char | 字符型 | 2 Byte | 0 ~ 65535 默认值是0 |
short | 短整型 | 2 Byte | -32768(-215) ~ 32767(215 - 1) 默认值是0 |
int | 整型 | 4 Byte | -2,147,483,648(-231) ~ 2,147,483,647(231 - 1) 默认值是0 |
long | 长整型 | 8 Byte | -9,223,372,036,854,775,808(-263) ~ 9,223,372,036,854,775,807(263 - 1) 默认值是0L |
float | 单精度浮点 | 4 Byte | 默认值是0.0f |
double | 双精度浮点 | 8 Byte | 默认值是0.0d |
运算符
与 C/C++ 类似, 不赘述
声明变量
与 C/C++ 类似, 需要注意的是, 声明引用数据类型的变量后需要实例化 ( new 一个对象) 才能使用.
final 关键字
在声明变量时, final
表示这是最终的、不可更改的结果,被
final
修饰的变量只能被赋值一次,赋值后不再改变。
1 | final double PI = 3.1415926; |
数组
数组是引用数据类型.
1 | // 数据类型[]...[] 数组名 = new 数据类型[大小1]...[大小n]; |
流程控制
与 C/C++ 基本一致, 需要注意的是, Java 提供了特化的 goto
,
即带标签的 break
和 continue
.
1 | // 代码仅做演示, 无实际意义 |
此外, Java 严格要求条件判断必须使用 boolean
类型, 而非
C/C++ 中使用 0 和 非0 即可.
面向对象
类和实例
类可以理解为一种对象模板, 定义了如何创建实例, 所以, 类应当视作一种数据类型.
实例是根据类创建的对象, 可以根据类创建多个实例, 每个实例的属性可能各不相同.
创建类和实例
创建一个类即定义一个 class
1 | class Frog{ |
一个 class
可以有多个属性, 比如上面的
isAngry
和 life
, 也可以有多个方法, 比如上面的
moHa()
.
public
和 private
是用来修饰属性和方法的,
public
表示可以被外部访问, private
表示不能被外部访问.
有了模板, 就可以创建真正的对象了, 创建对象实例需要使用
new
关键字.
1 | Forg exciting = new Forg(); |
方法
我们来为 Forg
类添加一些东西:
1 | class Frog{ |
定义方法和定义 C/C++ 中的函数类似, 特别是 C++.
格式:
1 | 修饰词列表 返回值类型 方法名(参数列表){ |
对于 private
属性, 可以通过方法来访问与修改, 通常命名为
getXXX()
和 setXXX()
.
与属性一样, 方法也有 private
和 public
之分, 前者只能被内部的方法调用.
this 变量
在方法内部, 可以使用一个隐含的变量 this
,
它始终指向当前实例, 在没有命名冲突的情况下可以省略
this
.
可变参数
可变参数用 类型...
定义, 可以看作数组类型.
构造方法
初始化实例的方法称为构造方法, 它与类同名, 没有返回值. 要调用构造方法,
必须使用 new
关键字.
在为编写构造方法时, 存在一个默认的构造方法, 既没有参数, 也没有执行语句.
需要注意的时如果自定义了一个构造方法(不论是有参还是无参), 默认构造方法就不会被创建.
构造方法之间也可以互相调用.
方法重载
方法名相同, 参数不同, 称为方法重载 (Overload
); 与 C++
类似, 不赘述.
继承
继承是 OOP 中非常强大的机制, 首先可以复用代码, 子类能获得父类的所有功能, 我们只需要为子类编写新的功能.
Java 中使用 extends
来实现继承:
1 | class Mogician extends Frog{ |
需要注意的是, 子类无法访问父类中使用 private
标记的部分,
如果需要让子类访问, 而又不想让外部访问, 可以使用
protected
.
父类使用 super
关键字来表示, 另外, 每个
class
的构造方法都会在初始位置调用 super()
,
也就是父类的构造方法 (如果没有显式调用, 编译器会帮你加上去,
某些情况则必须显式调用).
final
关键字在继承中还有一个作用: 阻止某个类被继承.
向上转型的一些问题请看传送门:
向下转型需要使用 instanceof
操作符来判断是不是某个类型.
重写
子类如果定义了一个与父类方法签名完全相同的方法, 则称为重写 (Override).
例:
1 | class A{ |
Override和Overload的不同在于前者的参数列表是相同的; 后者的参数列表是不同的, Overload方法可以看作新方法.
方法名和参数列表相同, 返回值不同是无法编译的.
@Override
的作用是告诉编译器, 这里有一个重写的方法,
从而让编译器进行检查.
需要注意的是 final
方法不能被重写.
重写Object方法
所有 class
直接或间接的继承自 Object()
,
Object()
中有几个重要的方法:
toString()
equals()
hashCode()
多态
讲了重写就可以讲多态了, 很显然, 由于转型、重写等的存在, 对象所对应的方法和声明的变量类型所对应的方法可能是不匹配的, 那么, 究竟该调用哪一个方法呢? 基于运行时的实际类型(而非声明的变量类型)的动态调用就被称之为多态.
接口
抽象类
讲接口之前要讲一下抽象类, 如果一个类中没有包含足够的信息来描绘一个具体的对象, 这样的类就是抽象类.
抽象类除了不能实例化对象之外, 类的其它功能依然存在, 成员变量、成员方法和构造方法的访问方式和普通类一样.
抽象类不能被实例化, 所以必须被继承后才能使用.
在类的修饰词列表中加上 abstract
即可定义抽象类.
接口
如果一个抽象类没有属性, 且所有方法都是抽象方法, 就可以改写为接口.
接口用 interface
声明, 接口中没有属性和方法的具体实现,
只有方法的声明.
接口的使用
要实现某个 interface
时只需要使用
implements
关键字.
一个类可以实现多个接口, 相关接口用逗号隔开即可.
当接口中的某个方法用 default
修饰时,
该方法可以不被重写.
1 | interface Frog{ |
接口也有继承权, 同样使用 extends
关键字.
static
当属性或方法被 static
修饰时,
我们称之为静态属性或静态方法.
访问它们建议使用 类名.名称
静态属性和静态方法是共享的, 无论某个类有多少个对象, 其中的一个静态属性在内存中只有一份, 而且不论是哪个对象对其做出修改, 所有对象中的静态属性都被修改.
因为静态属性和静态方法不属于实例, 所以接口中可以有静态属性,
但是必须用 final
修饰 (当然, 因为只能是
public static final
, 所以忘了写编译器也会贴心的加上).
进阶
烂尾了