定义和使用类
Java中所有代码都必须是类的一部分, 大部分代码都是在方法中编写的
错误示范
1
2
3
4
5
|
public class Dog {
public static void makeNoise() {
System.out.println("Bark!");
}
}
|
如果我们运行以上代码, 会收到报错:
1
2
3
|
$ java Dog
Error: Main method not found in class Dog, please define the main method as:
public static void main(String[] args)
|
- 定义的
Dog 类并不执行任何操作, 只是定义了 Dog 的一些功能
- 要运行该类, 需要添加一个
Main 方法, 来运行 Dog 中的方法
修正后
我们通过创建一个单独的 DogLaucher 来运行 Dog 中的方法
1
2
3
4
5
|
public class DogLauncher {
public static void main(String[] args) {
Dog.makeNoise();
}
}
|
1
2
|
$ java DogLauncher
Bark!
|
- 使用另一个的类有时被称为它的客户端(client)
实例变量与对象实例化
当 Dog 类需要向下细分时, 我们不需要从头编写一些重复的代码, 而是可以选择通过继承+修改等方式, 实现新的类
创建单独的类别
1
2
3
4
5
6
7
8
9
10
11
|
public class TinyDog {
public static void makeNoise() {
System.out.println("yip yip yip yip");
}
}
public class MalamuteDog {
public static void makeNoise() {
System.out.println("arooooooooooooooo!");
}
}
|
创建 Dog 类实例
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Dog {
public int weightInPounds;
public void makeNoise() {
if (weightInPounds < 10) {
System.out.println("yipyipyip!");
} else if (weightInPounds < 30) {
System.out.println("bark. bark.");
} else {
System.out.println("woof!");
}
}
}
|
这里我们给 Dog 类定义一个属性, 是其体重
然后根据不同的体重, 决定其不同的行为
1
2
3
4
5
6
7
8
|
public class DogLauncher {
public static void main(String[] args) {
Dog d;
d = new Dog();
d.weightInPounds = 20;
d.makeNoise();
}
}
|
这里, 我们将 Dog 类实例化, 得到一个实例
并为 d 的属性赋值, 然后观察其执行的行为
- Java 中的
Object是任何类的实例
Dog 类有自己的变量,也称为实例变量或非静态变量 。这些必须在类内声明
- 我们在
Dog 类中创建的方法没有 static 关键字。我们将此类方法称为实例方法或非静态方法
- 要调用
makeNoise 方法,我们必须首先使用 new 关键字实例化 Dog,然后制作特定的 Dog 吠叫
- 我们调用了
d.makeNoise() 而不是 Dog.makeNoise()
- 一旦对象被实例化,就可以将其分配给适当类型的声明变量
- 类的变量和方法也称为类的成员(members)
- 使用点表示法访问类的成员
我的问题: 为什么感觉 d 被定义了两遍
我觉得 Dog d; 和 d = new Dog(); 都是在定义 d
这涉及到 java 中对象和引用的区别
Dog d;
这句话的意思是:
- 定义了一个 变量
d,类型是 Dog
- 但是此时
d 只是一个引用(reference),它还没有指向任何对象
- 就像是声明了“我有一只狗的指针”,但实际还没给它拴上一只真正的狗
如果你此时直接写 d.makeNoise();,会报错 NullPointerException,因为 d 还没有指向任何对象。
2. d = new Dog();
这句话才是 真正创建了一只狗(在堆里 new 出一个 Dog 对象),然后让 d 指向它
new Dog() 会在内存里开辟空间,构造一只狗对象
d = ... 是把这个对象的地址赋值给 d
- 之后你就可以通过
d 来访问这只狗,比如 d.weightInPounds = 20;
- 合并写法
上面两步经常合并成一步:
Dog d = new Dog();
等价于:
Dog d; d = new Dog();
在 Java 中构造函数
1
2
3
4
5
6
|
public class DogLauncher {
public static void main(String[] args) {
Dog d = new Dog(20);
d.makeNoise();
}
}
|
这里, 实例化是参数化的(实例化过程中直接传入参数), 能够节省一些赋值时的混乱
但如果想这样做, 需要在 Dog 类中添加一个构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class Dog {
public int weightInPounds;
public Dog(int w) {
weightInPounds = w;
}
public void makeNoise() {
if (weightInPounds < 10) {
System.out.println("yipyipyip!");
} else if (weightInPounds < 30) {
System.out.println("bark. bark.");
} else {
System.out.println("woof!");
}
}
}
|
- 每当我们尝试使用
new 关键字和单个整数参数创建 Dog 时,都会调用具有签名 public Dog(int w) 的构造函数
- 和 python 中的
__init__ 方法非常相似
关于构造函数
- 构造函数必须和类名完全相同(包括大小写)
- 构造函数不能有返回类型, 连 void 都不行
- 构造函数可以有多个(重载)
- 如果不写构造函数, java 会自动生成一个无参构造函数
非静态的方法
这里的 makeNoise 在定义的时候并没有加 static, 也就是这个并不是一个静态方法
这种也被称为实例方法
通俗来讲, 如果一个方法需要调用一个实例的变量, 那这个方法必须是非静态的
数组实例化, 对象数组
数组实例化
1
2
3
4
5
6
7
8
|
public class ArrayDemo {
public static void main(String[] args) {
/* Create an array of five integers. */
int[] someArray = new int[5];
someArray[0] = 3;
someArray[1] = 4;
}
}
|
这里数组也是用 new 这个关键字进行实例化的
对象的数组
1
2
3
4
5
6
7
8
9
10
11
|
public class DogArrayDemo {
public static void main(String[] args) {
/* Create an array of two dogs. */
Dog[] dogs = new Dog[2];
dogs[0] = new Dog(8);
dogs[1] = new Dog(20);
/* Yipping will result, since dogs[0] has weight 8. */
dogs[0].makeNoise();
}
}
|
new 有两种不同的使用方式:
- 一次创建可以容纳两个
Dog 对象的数组
- 第二次创建每个实际
的 Dog
类方法与实例方法
Java 允许定义两种类型的方法:
- 类方法, 又称为静态方法
- 实例方法, 又称为非静态方法
举例与比较
现在有一个 Math 类, 其提供一个 sqrt 方法
若 sqrt 是静态的:
若 sqrt 是非静态的:
1
2
|
Math m = new Math();
x = m.sqrt(100);
|
同时具有实例和静态方法
当我们想比较两只狗的能力时, 可以添加一个静态方法:
1
2
3
4
5
6
|
public static Dog maxDog(Dog d1, Dog d2) {
if (d1.weightInPounds > d2.weightInPounds) {
return d1;
}
return d2;
}
|
然后通过以下方法调用:
1
2
3
|
Dog d = new Dog(15);
Dog d2 = new Dog(100);
Dog.maxDog(d, d2);
|
因为我们使用类名调用, 因此这个方法是一个静态方法
实现成一个功能相同的非静态方法:
1
2
3
4
5
6
|
public Dog maxDog(Dog d2) {
if (this.weightInPounds > d2.weightInPounds) {
return this;
}
return d2;
}
|
通过调用实例来调用此方法:
1
2
3
|
Dog d = new Dog(15);
Dog d2 = new Dog(100);
d.maxDog(d2);
|
静态变量
- 静态变量是类本身固有的属性
- 静态变量通过类名, 而非特定实例来访问
1
2
3
4
5
|
public class Dog {
public int weightInPounds;
public static String binomen = "Canis familiaris";
...
}
|
Dog.binomen
public static void main(String[] args)
用于 main 方法的声明:
public:到目前为止,我们所有的方法都以这个关键字开头
static:它是一个静态方法,不与任何特定实例相关联
void:它没有返回类型
main:这是方法的名称
String[] args:这是传递给 main 方法的参数
命令行参数
由于 main 是由 Java 解释器本身而不是另一个 Java 类调用的,因此解释器的工作是提供这些参数。它们通常引用命令行参数
1
2
3
4
5
|
public class ArgsDemo {
public static void main(String[] args) {
System.out.println(args[0]);
}
}
|
1
2
|
$ java ArgsDemo these are command line arguments
these
|