Java | 类的五大成员
类的五大成员:属性、方法、构造器、代码块、内部类。
# 属性
属性也称为成员变量。
声明属性的语法格式:
[修饰符] 数据类型 属性名;
在其他类中属性的赋值:
对象.属性名 = 值;
声明属性的位置:必须在类中,其他成员(方法、构造器等)的外面。
# 属性的特点
属性有默认值。
每一个对象的属性是独立的。
# 属性的默认值
基本数据类型:
byte, short, int, long
默认值为0
float, double
默认值为0.0
char
默认值为\u0000
boolean
默认值为false
引用数据类型:
- 类、数组、接口默认值为
null
# 变量的分类
按照变量声明的“位置”分为可分为:
局部变量
成员变量
实例变量:没有
static
修饰的属性。类变量:使用
static
修饰的属性。
# 局部变量
局部变量的声明的位置:方法的形参列表、方法体、代码块中。
局部变量的初始化:形参的初始化,必须在调用时,由实参赋值;其他的局部变量,必须手动初始化。
局部变量存放位置:栈。
局部变量的生命周期:当代码执行到局部变量的声明处开始,到它的作用域结束而结束。
局部变量可用的修饰符:final。
# 成员变量
成员变量的声明的位置:类中、方法和代码块等外面。
成员变量的初始化:有默认值。可以显式初始化、使用构造器初始化,或者定义 set 方法可以再次修改值。
成员变量存放位置:实例变量存放在堆中;类变量存放在方法区中。
成员变量的生命周期:随着对象的创建而创建,随着对象被垃圾回收而消亡。每一个对象的成员变量是独立的。
成员变量可用的修饰符:访问修饰符(private,默认,protected,public)、static、final、volatile 等。
# 方法
方法(method),又称为函数(function),代表的是一个独立的功能。例如:
Math.sqrt(m)
这个sqrt(m)
方法,返回m
的平方根。System.out.println()
这个println()
方法打印()
中的内容。
把代码封装到一个方法中的目的,简单的实现功能的复用。
# 方法的要求和特点
必须先声明后使用。
不调用不执行,调用一次执行一次。
调用时必须遵循一定的格式。
方法声明的位置必须在类中,并且在方法外。
# 方法的参数传递机制
当形参的数据类型是基本数据类型时,实参给形参传递的是“数据值”,“形参”是“实参”的一个“副本”,对形参的修改不会影响实参。主方法和你所定义的方法在内存中是两个互相独立的空间,当你调用自己定义的方法执行完之后,它就会撤掉,变成垃圾准备回收了。
当形参的数据类型是引用数据类型时,实参给形参传递的是“地址值”,意味着“形参”和“实参”同时指向同一个对象,那么“形参”修改了它的属性,也意味着“实参”的属性也被修改了。
# 方法的重载
在同一个类中,出现了两个或多个“方法名称相同”、“形参列表不同”的方法,这些方法我们称为“方法的重载”,和返回值类型无关。
形参列表不同:个数、数据类型不同。
# 构造器
构造器,又称为构造方法,构造器可以在创建对象的同时,为属性初始化,或赋初始值。
# 构造器的特点
所有的类都有构造器。
构造器可以重载。
如果没有声明构造器,那么编译器将会自动生成一个默认的无参构造器。
如果手动声明了构造器,那么编译器就不会再自动生成无参构造了,如果你还需要无参构造,那么必须自己定义。
构造器的名称必须与类名相同,并且没有返回值类型,也不需要写 void。
# 代码块
代码块的作用:为属性初始化。
代码块分为以下两种:
静态代码块:为静态属性初始化,或者说辅助类初始化。
非静态代码块:为非静态属性初始化,或者说辅助实例(对象)初始化。
# 代码块执行
静态代码块:在类初始化时执行,只执行一次。
非静态代码块:在实例初始化时执行,创建一个对象,执行一次。
# 类初始化
每一个类,编译器会自动生成一个 clinit()
,称为类初始化方法。子类初始化时,如果父类没有初始化,会先初始化父类。
这个方法的方法体由以下两部分组成:
静态变量的显式赋值语句。
静态代码块中的语句。
这两个部分,谁在上面谁先执行。
# 实例初始化
每一个构造器,编译器会自动生成一个对应的 init()
,称为实例初始化方法。创建子类对象时,也会导致父类的实例初始化方法执行。
这个方法的方法体由以下三部分组成:
非静态变量的显式赋值语句。
非静态代码块中的语句。
对应构造器的语句。
第一部分和第二部分仍然是谁在上面谁先执行,构造器永远是最后执行。
# 初始化顺序
父类初始化 clinit
>>> 子类初始化 clinit
>>> 父类的实例初始化 init
>>> 子类的实例初始化 init
一开始都是静态的先初始化。
# 内部类
一个类的内部又完整的嵌套了另外一个类结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类。内部类是类的五大成员之一,其最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
# 内部类的分类
定义在外部类的局部位置上:
局部内部类
匿名内部类
定义在外部类的成员位置上:
成员内部类
静态内部类
# 局部内部类
局部内部类是定义在外部类的局部位置,比如方法体、代码块中,并且有类名。
class OuterClass { // 外部类
// ...
public void method() {
// ...
class InnerClass { // 局部内部类
// ...
}
}
}
2
3
4
5
6
7
8
9
特点:
可以直接访问外部类的所有成员,包含私有的。
不能添加访问修饰符,但可以使用非访问修饰符
final
来修饰。如果外部类和局部内部类的成员重名时,默认遵循就近原则。
作用域:
- 仅在定义它的方法体或代码块中。
成员的访问方法:
局部内部类访问外部类的成员:直接访问。如果成员重名,需要用
<外部类类名>.this.<成员名>
去访问。只能在其作用域中访问局部内部类的成员和创建局部内部类的对象。
# 匿名内部类
局部内部类是定义在外部类的局部位置,比如方法体、代码块中,并且没有类名。
interface Product { // 接口
// ...
void show();
}
public class Main {
public static void main(String[] args) {
// ...
m1(new Product() { // 匿名内部类
@Override
public void show() {
// ...
}
});
}
public static void m1(Product product) {
// ...
product.show();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
特点:
没有名字,不能有构造方法。
匿名内部类可以当作实参直接传递。
匿名内部类使用单独的块表示初始化块
匿名内部类是与继承或实现合并在一起的没有名字的内部类。
匿名内部类不利于代码的重用,一般在确定此内部类只会使用一次时,才会使用匿名内部类。
语法格式:
new 实现接口() {
//匿名内部类类体部分
}
2
3
new 父类构造器(实参列表) {
//匿名内部类类体部分
}
2
3
这两种格式分别对应两种实现,一种是接口的实现,另一种是抽象类的实现。对于实现接口,由于接口是没有构造函数的,所以实参列表一定是空的。
# 成员内部类
成员内部类是定义在外部类的成员位置,并且没有 static
修饰。
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
class InnerClass { // 成员内部类
// ...
}
}
2
3
4
5
6
7
8
9
10
特点:
可以直接访问外部类的所有成员,包含私有的。
可以添加任意访问修饰符。
如果外部类和成员内部类的成员重名时,默认遵循就近原则。
作用域:
- 和外部类的其他成员一样,为整个类体。
成员的访问方法:
成员内部类访问外部类的成员:直接访问。如果成员重名,需要用
<外部类类名>.this.<成员名>
去访问。外部类访问成员内部类的成员:先创建成员内部类对象,再访问。
在外部其他类创建成员内部类对象的方法:
/**
* 第一种方法
*/
public class Main {
public static void main(String[] args) {
// 创建外部类对象
OuterClass outerClass = new OuterClass();
// 使用外部类对象创建一个成员内部类对象
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
}
}
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
class InnerClass { // 成员内部类
// ...
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 第二种方法
*/
public class Main {
public static void main(String[] args) {
// 创建外部类对象
OuterClass outerClass = new OuterClass();
// 调用外部类的 getInnerClass 方法获取成员内部类对象
OuterClass.InnerClass innerClass = outerClass.getInnerClass();
}
}
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
class InnerClass { // 成员内部类
// ...
}
public InnerClass getInnerClass() {
return new InnerClass(); // 返回成员内部类对象
}
}
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
/**
* 第三种方法
*/
public class Main {
public static void main(String[] args) {
// 创建外部类匿名对象,紧接着创建成员内部类对象,其本质和第一种方法一样,但这样更加简洁
OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
}
}
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
class InnerClass { // 成员内部类
// ...
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 静态内部类
静态内部类是定义在外部类的成员位置,并且有 static
修饰。
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
static class InnerClass { // 静态内部类
// ...
}
}
2
3
4
5
6
7
8
9
10
特点:
可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员。
可以添加任意访问修饰符。
如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则。
作用域:
- 和外部类的其他成员一样,为整个类体。
成员的访问方法:
静态内部类访问外部类的成员:直接访问所有静态成员。如果成员重名,需要用
<外部类类名>.<静态成员名>
去访问。外部类访问静态内部类的成员:先创建静态内部类对象,再访问。
在外部其他类创建静态内部类对象的方法:
/**
* 第一种方法
*/
public class Main {
public static void main(String[] args) {
// 无需创建外部类对象,直接通过 <外部类类名>.<静态内部类类名> 创建
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
}
}
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
static class InnerClass { // 静态内部类
// ...
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 第二种方法
*/
public class Main {
public static void main(String[] args) {
// 调用外部类的 getInnerClass 静态方法获取静态内部类对象
OuterClass.InnerClass innerClass = OuterClass.getInnerClass();
}
}
class OuterClass { // 外部类
// ...
public void method() {
// ...
}
static class InnerClass { // 静态内部类
// ...
}
public static InnerClass getInnerClass() {
return new InnerClass(); // 返回静态内部类对象
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25