钾肥喵的窝

我在 CODING 部署的 Hexo 博客

0%

钾肥喵的Java笔记

入门

环境

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
2
3
4
5
6
7
8
public class Hello{
public static void main(String args[]){
// method body
}
public int aMethod{
// method body
}
}

注释

与 C/C++ 基本一致, 但是多了一种文档注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 文档注释可以用来自动创建文档
*
* @auther JiaFeiMiao
* @version 0.0.1
*/
public class Hello {
// 这是一个单行注释
public static void main(String[] args) {
System.out.println("Hello, world!");
/*
这里有一个
多行
注释
*/
}
}

基本数据类型

类型名 意义 存储空间 取值
boolean 布尔类型 未规定 truefalse(默认)
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
2
3
// 数据类型[]...[] 数组名 = new 数据类型[大小1]...[大小n];
int[] aArray = new int[19260817];
int[][] a_2D_Array = new int[192608][17];

流程控制

与 C/C++ 基本一致, 需要注意的是, Java 提供了特化的 goto, 即带标签的 breakcontinue.

1
2
3
4
5
6
7
8
9
10
// 代码仅做演示, 无实际意义
label:
for (int i = 0; i < 19260817; i++){
if (i == 1926){
break label;
}
else{
continue label;
}
}

此外, Java 严格要求条件判断必须使用 boolean 类型, 而非 C/C++ 中使用 0 和 非0 即可.

面向对象

类和实例

类可以理解为一种对象模板, 定义了如何创建实例, 所以, 类应当视作一种数据类型.

实例是根据类创建的对象, 可以根据类创建多个实例, 每个实例的属性可能各不相同.

创建类和实例

创建一个类即定义一个 class

1
2
3
4
5
6
7
8
class Frog{
public boolean isAngry;
private int life;
public boolean moHa(){
life--;
return life > 0;
}
}

一个 class 可以有多个属性, 比如上面的 isAngrylife, 也可以有多个方法, 比如上面的 moHa().

publicprivate 是用来修饰属性和方法的, public 表示可以被外部访问, private 表示不能被外部访问.

有了模板, 就可以创建真正的对象了, 创建对象实例需要使用 new 关键字.

1
Forg exciting = new Forg();

方法

我们来为 Forg 类添加一些东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Frog{
public boolean isAngry;
private int life;
Forg(){
isAngry = true;
life = 19260817;
}
Forg(boolean isAngry, int life){
this.isAngry = isAngry;
this.life = life;
}
public boolean moHa(){
life--;
return life > 0;
}
private void revive(int life){
this.life = life;
}
public boolean getLife(){
return life;
}
public void setLife(int life){
revive(life);
}
public int calculateLife(int... records){
for (int i = 0; i < records.length; i++){
life -= records[i];
}
return life;
}
}

定义方法和定义 C/C++ 中的函数类似, 特别是 C++.

格式:

1
2
3
修饰词列表 返回值类型 方法名(参数列表){
方法体
}

对于 private 属性, 可以通过方法来访问与修改, 通常命名为 getXXX()setXXX().

与属性一样, 方法也有 privatepublic 之分, 前者只能被内部的方法调用.

this 变量

在方法内部, 可以使用一个隐含的变量 this, 它始终指向当前实例, 在没有命名冲突的情况下可以省略 this.

可变参数

可变参数用 类型... 定义, 可以看作数组类型.

构造方法

初始化实例的方法称为构造方法, 它与类同名, 没有返回值. 要调用构造方法, 必须使用 new 关键字.

在为编写构造方法时, 存在一个默认的构造方法, 既没有参数, 也没有执行语句.

需要注意的时如果自定义了一个构造方法(不论是有参还是无参), 默认构造方法就不会被创建.

构造方法之间也可以互相调用.

方法重载

方法名相同, 参数不同, 称为方法重载 (Overload); 与 C++ 类似, 不赘述.

继承

继承是 OOP 中非常强大的机制, 首先可以复用代码, 子类能获得父类的所有功能, 我们只需要为子类编写新的功能.

Java 中使用 extends 来实现继承:

1
2
3
4
5
6
7
8
class Mogician extends Frog{
public int level;
public String name;
...
public void poem{
System.out.println("苟利国家生死以, 岂因祸福避趋之");
}
}

需要注意的是, 子类无法访问父类中使用 private 标记的部分, 如果需要让子类访问, 而又不想让外部访问, 可以使用 protected.

父类使用 super 关键字来表示, 另外, 每个 class 的构造方法都会在初始位置调用 super(), 也就是父类的构造方法 (如果没有显式调用, 编译器会帮你加上去, 某些情况则必须显式调用).

final 关键字在继承中还有一个作用: 阻止某个类被继承.

向上转型的一些问题请看传送门:

Java中属性的继承|一道判断题引发的思考

向下转型需要使用 instanceof 操作符来判断是不是某个类型.

重写

子类如果定义了一个与父类方法签名完全相同的方法, 则称为重写 (Override).

例:

1
2
3
4
5
6
7
8
9
10
11
class A{
void fun(){
...
};
}
class B extends A{
@Override
void fun(){
...
}
}

Override和Overload的不同在于前者的参数列表是相同的; 后者的参数列表是不同的, Overload方法可以看作新方法.

方法名和参数列表相同, 返回值不同是无法编译的.

@Override 的作用是告诉编译器, 这里有一个重写的方法, 从而让编译器进行检查.

需要注意的是 final 方法不能被重写.

重写Object方法

所有 class 直接或间接的继承自 Object(), Object()中有几个重要的方法:

  • toString()

  • equals()

  • hashCode()

多态

讲了重写就可以讲多态了, 很显然, 由于转型、重写等的存在, 对象所对应的方法和声明的变量类型所对应的方法可能是不匹配的, 那么, 究竟该调用哪一个方法呢? 基于运行时的实际类型(而非声明的变量类型)的动态调用就被称之为多态.

接口

抽象类

讲接口之前要讲一下抽象类, 如果一个类中没有包含足够的信息来描绘一个具体的对象, 这样的类就是抽象类.

抽象类除了不能实例化对象之外, 类的其它功能依然存在, 成员变量、成员方法和构造方法的访问方式和普通类一样.

抽象类不能被实例化, 所以必须被继承后才能使用.

在类的修饰词列表中加上 abstract 即可定义抽象类.

接口

如果一个抽象类没有属性, 且所有方法都是抽象方法, 就可以改写为接口.

接口用 interface 声明, 接口中没有属性和方法的具体实现, 只有方法的声明.

接口的使用

要实现某个 interface 时只需要使用 implements 关键字.

一个类可以实现多个接口, 相关接口用逗号隔开即可.

当接口中的某个方法用 default 修饰时, 该方法可以不被重写.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Frog{
void poem();
void moHa();
default void naive();
}
interface HongKongReporter{
void run();
}
class Mogician implements Frog, HongKongReporter{
public int life;
@Override
public void poem(){
System.out.println("苟利国家生死以, 岂因祸福避趋之");
}
@Override
public void moHa(){
life--;
}
@Override
public void run(){
System.out.println("跑的比谁都快");
}
}

接口也有继承权, 同样使用 extends 关键字.

static

当属性或方法被 static 修饰时, 我们称之为静态属性或静态方法.

访问它们建议使用 类名.名称

静态属性和静态方法是共享的, 无论某个类有多少个对象, 其中的一个静态属性在内存中只有一份, 而且不论是哪个对象对其做出修改, 所有对象中的静态属性都被修改.

因为静态属性和静态方法不属于实例, 所以接口中可以有静态属性, 但是必须用 final 修饰 (当然, 因为只能是 public static final, 所以忘了写编译器也会贴心的加上).

进阶

烂尾了