(2021.11.13 Sat)
定义类
通过关键字class
和名称定义类
class DemoClass {
// class body
}
类的继承使用extends
关键字。
class ChildClass extends DemoClass {
// class body
}
类ChildClass
继承了DemoClass
。
注意,Java中的类都默认是从Object
类派生而来,Object
是所有Java类的超类,于是有
class DemoClass extends Object {
// class body
}
定义类变量、实例变量和局部变量
类变量
类变量适用于整个类,而不是类的各个对象;适用于同一个类的不同对象间共享信息或记录类级信息。用关键字static
声明变量。
static int SUM;
static final int MAX_O = 0;
习惯上Java类变量名用大写,以便与其他变量区分,但并非必须。
定义实例变量
实例变量的声明和定义与局部变量几乎相同,区别在于实例变量位于类定义中。
在方法定义外声明且没有使用关键字static
的变量是实例变量。习惯上石林变量位于第一行类变量定义后声明的。
class MRobot extends Robot{
String status;
int speed;
}
在局部变量作用域内调用实例变量
如果局部变量和实例变量的名字相同,则在作用域内的该变量名只想局部变量。如要调用实例变量,需要使用关键字this
。this
关键字用于引用当前对象(实例)。很多情况下,不需要显式的使用this
,因为是默认的。例如,可以只使用变量名称来引用当前类中定义的实例变量和方法的调用。由于this
是指向当前实例的引用,因此只能在实例方法中的定义体内使用它。在类方法(用关键字static
声明的方法)中,不能使用this
关键字。
class ScopeTest{
int iv = 100; // 定义一个实例变量
void printTest(){
int iv = 900; // 局部变量
System.out.print('local var: ' + iv);
System.out.print('instance var: ' + this.iv); //调用实例变量
}
public static void main(String[] arguments){
// stuff
}
}
避免出现这种情况的最好方法是,了解类定义中的所有变量,避免使用重名的局部变量。
Java中引用变量时,从最里面的作用域向外查找其定义。
定义方法
方法含四个部分
- 方法名
- 返回的对象类型或基本数据类型
- 参数列表
- 方法体
其中的方法明和参数列表构成了方法的特征标。返回的类型可以是数据类型,也可以是类。如果返回类型为void
,则该方法不返回任何值。如果类型不返回void
,则方法中需要用关键字return
显示的返回值。
同一个类中包含多个名称相同,但是特征标不同的方法,叫做方法重载。
参数传递
参数传递给方法时,对象是按引用传递,也就是在方法中对该对象所作的任何操作都将影响原来的对象。这样的对象包括数组和数组的对象,而基本数据类型和字符串是按值传递,因此在方法中无法修改原来的值。
类方法
类方法与实例方法的关系如同类变量与实例变量的关系。类方法可被类的任何实例使用,也可被其他类使用。与实例方法不同,调用类方法时,不需要有类的对象。比如Java库中的System
类。
System.exit(0);
long now = System.currentTimeMillis();
定义类方法时,需要在方法定义前加上关键字static
。如果方法名前有关键字static
,则该方法是类方法。实例方法只能在对象中运行,而不能在类中运行。不同于实例方法,类方法不能被继承,因此在子类中不能覆盖超类的类方法。
main方法
main
方法也是类方法,因为声明时有关键字static
。main
方法的特殊性在于,它的存在使得所在类成为应用程序的入口类。一个项目中有多个Java文件和类,但只有main
方法所在的类成为入口类,也就是主类。
main
方法的特征标如下:
publish static void main(String[] arguments){
//
}
各项含义:
-
public
:该方法对其他类和对象也是可用的。 -
static
:类方法 -
void
:不返回任何值 -
String[] arguments
:接受一个参数,即字符串数组。该参数用于存储命令行参数。arguments
用于存储参数列表的字符串数组,可以自定义其名字。
在Java项目中,可将一个类指定为项目的主类,项目被打包成Java归档(JAR)文件后,如果该JAR文件被执行,将运行主类。
参数传递给Java应用程序
在命令行中运行下面指令
java Echo April 450 "this is a string"
其中的java
是解释器名称,Echo
是Java应用程序名称,其他内容是用空格隔开的传递给程序的三个参数。对于参数中含有空格的,必须用引号将其括起。
(2021.11.14 Sun)
创建同名方法/方法重载
类中有些方法会同名,名称相同的方法通过两个因素区分:
- 参数个数
- 参数的数据类型和对象
这两个因素都是方法特征标。使用多个名称相同但是特征标不同的方法被称作重载。
注意,只要参数列表不同,Java就允许对方法进行重载。而如果仅仅是返回值的类型不同,在Java中不能通过类的编译。
在下面这个例子中,Box
类中的buildBox
方法有多种定义,都返回Box
类型本身。
import java.awt.Point;
class Box {
int x1 = 0;
int y1 = 0;
int x2 = 0;
int y2 = 0;
Box buildBox(int x1, int y1, int x2, int y2) {
this.x1 = x1; // 局部变量和实例变量同名,所以用this调用
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
return this;
}
// 两个方法的返回值都是Box类
Box buildBox(Point topLeft, Point bottomRight) {
x1 = topLeft.x;
y1 = topLeft.y;
x2 = bottomRight.x;
y2 = bottomRight.y;
return this;
}
...
上面的重载方法还可以使用更简洁的形式,
Box buildBox(int x1, int y1, int x2, int y2) {
// definition
}
Box buildBox(Point topLeft, Point bottomRight) {
return buildBox(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
}
构造函数
构造函数是对象被创建时调用的方法。与其他方法不同,构造函数不能被直接调用。构造函数可以重载。使用new
关键字创建类的实例时,Java做了下面三件事:
- 为对象分配内存
- 初始化对象的实例变量:赋予初值或设置默认值(数字为0,对象为null,布尔值为
false
,字符值为'\0') - 调用类的构造函数
创建类时,如果类没有构造函数,Java将隐式的提供一个不接受任何参数的构造函数,并调用构造函数来创造其对象。
如果类包含接受一个或多个参数的构造函数,则仅当这个类有不接受任何参数的构造函数时,才能调用这样的构造函数。
基本构造函数
构造函数与常规方法相似,但有3点不同:
- 构造函数名称总是与类名相同
- 没有返回类型
- 不能使用
return
语句返回一个值
class MarsRobot {
String status;
int speed;
int power;
//构造函数如下
MarsRobot(String in1, int in2, int in3) {
status = in1;
speed = in2;
power = in3;
}
}
创建对象
MarsRobot curiosity = new MarsRobot('exploring', 5, 200);
调用另一个构造函数
也就是构造函数的重载,格式为
this(arg1, arg2, arg3);
class Circle {
int x, y, radius;
Circle(int xPoint, int, yPoint, int radiusLength) {
this.x = xPoint;
this.y = yPoint;
this.radius = radiusLength;
}
// 构造函数的重载和调用
Circle(int xPoint, int yPoint) {
this(xPoint, yPoint, 1);
}
}
覆盖方法
当调用对象的方法时,Java将在对象的类中查找方法的定义。如果没有找到,将在超类中查找;如果没有找到,将继续沿类层次结构向上查找,直到找到方法的定义为止。继承能够在子类中重复定义和使用方法,而无须复制代码。
创建覆盖现有方法的方法
要覆盖方法,只需要在子类中创建一个特征标(名称、返回值类型和参数列表)和超类相同的方法即可。
调用原来的方法
调用超类中已经实现的方法的原因如下:
- 完全替换原来的方法定义
- 扩展原来的方法,加入其他行为
有时候并非完全覆盖原来的方法,仅是调用后做修改。此时可使用super
关键字。
格式如
super.methodName(...);
void doMethod(String a, String b) {
// something
super.doMethod(a, b);
// something
}
覆盖构造函数
调用或覆盖超类中的方法使用的指令如前面所述,使用关键字super
,而构造函数没有可供调用的方法名,因此格式如下
super(arg1, arg2, ...);
Reference
1 R. Cadenhead著,袁国忠译,21天学通Java(第7版),中国工信出版集团,人民邮电出版社