Java面向对象与权限修饰符、final关键字、代码块及内部类
约 1542 个字 315 行代码 预计阅读时间 9 分钟
权限修饰符
在Java中,一共有4种访问修饰符,分别是public
、protected
、default
和private
,下面是访问权限表:
| public | protected | default | private |
同类 | 可以 | 可以 | 可以 | 可以 |
同包不同类 | 可以 | 可以 | 可以 | 不可以 |
不同包父子类 | 可以 | 可以 | 不可以 | 不可以 |
不同包且非父子类 | 可以 | 不可以 | 不可以 | 不可以 |
从上表可以看出来,public
具有最大访问权限,private
具有最小访问权限
在实际开发中,一般建议按照下面的方式使用权限修饰符(除非有特殊要求):
- 成员变量(属性):
private
修饰(封装思想) - 成员方法:
public
修饰(便于调用) - 构造方法:
public
修饰(便于创建对象)
final
关键字
在Java中,final
关键字一般表示「最后一个」,具体到指定成员时表现出不同的效果:
final
修饰类:被final
修饰的类无法被继承,理解为「最后一个类」,例如 public final class A{}
final
修饰成员方法:被final
修饰的方法无法被重写,理解为「最后一个方法」,例如public final void method(){}
final
修饰局部变量:被final
修饰的局部变量无法被二次赋值(只要是第一次赋值都允许),理解为「最后一个局部变量赋值」,例如final int a = 1;
final
修饰对象引用:被final
修饰的对象引用一旦指向了一个对象,将无法指向其他对象,理解为「最后一次对象引用」,例如final A a = new A();
final
修饰成员变量:被final
修饰的成员变量必须给定初始值,并且无法通过赋值行为再次为成员变量赋值,例如final String name = "zhangsan";
注意:
- 因为
final
修饰类后对应类后该类不可以被继承,修饰成员方法后该方法不可以被重写,所以final
不可以与abstract
一起使用,因为final
关键字要求不被继承或重写,但是abstract
要求继承且重写对应方法 final
修饰局部变量时表示不能二次赋值,但不代表变量未初始化时不可以赋值,例如下面的代码:
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12 | public class Test1 {
public static void main(String[] args) {
// final修饰局部变量,初始化时属于第一次赋值
final int a = 1;
// a = 2; // 第二次赋值报错
// final修饰的局部变量
final int b;
b = 2; // final修饰的局部变量,未初始化时,此时属于第一次赋值
// b = 3; // 第二次赋值报错
}
}
|
代码块
在Java中,代码块分为静态代码块和非静态代码块
非静态代码块
不使用static
修饰的代码块,写法如下:
非静态代码块在对象中时,会优先于构造函数执行,并且有多少个对象就执行几次,例如下面的代码:
Java |
---|
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 | public class CodeBlockTest {
int num;
public CodeBlockTest(int num) {
this.num = num;
System.out.println("我是构造函数");
}
{
System.out.println("我是非静态代码块");
}
}
// 测试
public class Test1 {
public static void main(String[] args) {
CodeBlockTest codeBlockTest1 = new CodeBlockTest(10);
CodeBlockTest codeBlockTest2 = new CodeBlockTest(10);
}
}
输出结果:
我是非静态代码块
我是构造函数
我是非静态代码块
我是构造函数
|
静态代码块
使用static
修饰的代码块即为静态代码块,写法如下:
静态代码块与非静态代码块一样,在类中时,创建对象会优先于构造方法执行,但是静态代码块只会在第一次创建对象时执行,例如下面的代码:
Java |
---|
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 | public class StaticCodeBlockTest {
int num;
public StaticCodeBlockTest(int num) {
this.num = num;
System.out.println("我是构造函数");
}
static {
System.out.println("我是静态代码块");
}
}
// 测试
public class Test1 {
public static void main(String[] args) {
StaticCodeBlockTest staticCodeBlockTest = new StaticCodeBlockTest(10);
StaticCodeBlockTest staticCodeBlockTest1 = new StaticCodeBlockTest(10);
}
}
输出结果:
我是静态代码块
我是构造函数
我是构造函数
|
内部类
在Java中,内部类分为以下四种:
- 非静态成员内部类
- 静态成员内部类
- 局部成员内部类
- 匿名成员内部类
非静态成员内部类
当成员内部类没有被static
修饰时,称为非静态成员内部类,写法如下:
非静态成员内部类有以下的特点:
- 可以被
final
或abstract
修饰 - 内部类成员与普通类基本一致
- 可以访问外部类的成员
- 外部类如果想访问内部类非私有成员需要通过创建对象才可以访问非私有成员
- 当内部类中的方法存在局部变量、内部类成员变量与外部类成员变量同名时,优先访问局部变量,此时需要访问内部类成员变量,需要使用
this.成员变量
,如果需要访问外部类的成员变量,需要使用外部类.this.外部类成员变量
Note
注意,在JDK16之前,内部类成员(包括成员变量和成员方法)不可以是静态的,如果想要修改当前模块的JDK可以按照下面的方式进行:
File->Project Structure->Modules->选择需要改变JDK的模块->在Source页面改变Language Level为17->在Dependencies页面改变Module SDK(SDK即JDK)为17->OK
需要修改回JDK8重复上面的步骤,选择JDK8即可
改变项目JDK版本只需要在选择Module的位置选择Project即可
当需要创建非静态成员内部类对象时,按照下面的方法创建:
Java |
---|
| 外部类.内部类 对象名 = new 外部类().new 内部类();
|
例如下面的代码:
Java |
---|
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
32
33
34
35
36 | public class member_inner_class {
int a = 1;
class Inner{
int a = 2;
int inner = 3;
// JDK16后的版本支持静态成员变量
public static int num = 4;
void showInner(int a){
System.out.println(a); // 访问局部变量
System.out.println(this.a); // 访问当前内部类变量
System.out.println(member_inner_class.this.a); // 访问外部类变量
}
}
void showOuter(){
System.out.println(new Inner().inner);
}
}
// 测试
public class Test {
public static void main(String[] args) {
// 创建外部类对象
member_inner_class m = new member_inner_class();
// 创建内部类对象
member_inner_class.Inner mi = new member_inner_class().new Inner();
m.showOuter();
mi.showInner(5);
// 访问内部类中的静态成员
System.out.println(member_inner_class.Inner.num);
member_inner_class.Inner.method();
}
}
|
静态成员内部类
静态成员内部类和非静态成员内部类基本一致,不同的是:静态内部类不可以访问外部类中的非静态成员,创建静态成员内部类方式如下:
Java |
---|
| static class 类名 {
// 成员
}
|
创建静态成员内部类对象方式如下:
Java |
---|
| 外部类.内部类 对象名 = new 外部类.内部类()
|
例如下面的代码:
Java |
---|
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 | public class static_member_inner_class {
int a = 1;
static int b = 2;
static class Inner{
int a = 3;
int b = 4;
// 静态内部类在JDK8可以创建静态成员变量
static int num = 1;
void show(){
// System.out.println(static_member_inner_class.a); 静态内部类无法访问父类的非静态成员变量
System.out.println(static_member_inner_class.b); // 静态内部类可以访问父类的静态成员变量
System.out.println(a); // 静态内部类可以访问自己的成员变量
System.out.println(b);
System.out.println(num);
}
}
}
// 测试
public class Test {
public static void main(String[] args) {
// 创建外部类对象
static_member_inner_class sm = new static_member_inner_class();
// 创建内部类对象
static_member_inner_class.Inner inner = new static_member_inner_class.Inner();
inner.show();
}
}
|
局部内部类
定义与基本使用
在Java中,局部内部类可以理解为局部变量,定义在方法中或者代码块中,定义方式如下:
注意:局部内部类创建对象只能在内部类所在的外部类创建
例如下面的代码:
Java |
---|
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 | public class partial_inner_class {
int num = 1;
public void method() {
class Inner {
int num = 2;
public void showInner(int num) {
System.out.println(num); // 访问局部变量
System.out.println(this.num); // 访问内部类的成员变量
System.out.println(partial_inner_class.this.num); // 访问外部类的成员变量
}
}
// 创建内部类匿名对象并在外部类方法中调用内部类方法
new Inner().showInner(10);
}
}
// 测试
public class Test {
public static void main(String[] args) {
// 创建外部类对象
partial_inner_class p = new partial_inner_class();
// 调用外部类的方法
p.method();
}
}
|
接口类型/抽象类型作为方法参数传递和返回
Note
下面的代码以接口类型为例,抽象类型基本一致
-
接口/抽象类型作为方法参数传递时,传递的是对应实现类的对象
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | // 接口
public interface Test_interface {
void show();
}
// 实现类
public class Test_interfaceImpl implements Test_interface{
@Override
public void show() {
System.out.println("Test_interface接口实现类");
}
}
// 测试
public class Test {
public static void main(String[] args) {
Test_interfaceImpl testInterface = new Test_interfaceImpl();
method(testInterface); // 传递的是实现类的对象
}
public static void method(Test_interface ti){
ti.show(); // 多态,向上转型
}
}
|
-
接口/抽象类型作为方法参数返回时,返回的是对应实现类的对象
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | // 接口
public interface Test_interface {
void show();
}
// 实现类
public class Test_interfaceImpl implements Test_interface{
@Override
public void show() {
System.out.println("Test_interface接口实现类");
}
}
// 测试
public class Test {
public static void main(String[] args) {
Test_interface testInterface = getTestInterface();
}
public static Test_interface getTestInterface(){
return new Test_interfaceImpl();
}
}
|
局部类实现如下:
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | // 接口
public interface Test_interface {
void show();
}
// 测试
public class Test {
public static void main(String[] args) {
Test_interface testInterface = getTestInterface();
}
public static Test_interface getTestInterface() {
class Test_interfaceImpl_1 implements Test_interface{
@Override
public void show() {
System.out.println("局部内部类重写");
}
}
return new Test_interfaceImpl_1(); // 返回实现类(局部内部类)的对象,多态,向上转型
}
}
|
匿名内部类
定义匿名内部类
匿名内部类,即没有类名的内部类,可以替换前面的接口/抽象实现类,此时创建出的内部类即为对应接口/抽象类的实现类,创建方式如下:
Java |
---|
| // 调用接口/抽象类重写后的方法
new 接口类名/抽象类名() {
// 重写抽象类/接口类方法
}.重写后的方法名();
接口类/抽象类名 对象名 = new 接口类名/抽象类名 {
// 重写抽象类/接口类方法
};
对象名.重写的方法名();
|
匿名内部类基本使用
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | public class Test {
public static void main(String[] args) {
// 直接调用匿名内部类重写的方法
new Test_interface() {
@Override
public void show() {
System.out.println("匿名内部类实现Test_interface接口");
}
}.show();
// 使用对象调用匿名内部类重写的方法
Test_interface ti1 = new Test_interface() {
@Override
public void show() {
System.out.println("匿名内部类实现Test_interface接口");
}
};
ti1.show();
}
}
|
匿名内部类修改接口/抽象类型作为方法参数传递
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | // 接口
public interface Test_interface {
void show();
}
// 测试
public class Test {
public static void main(String[] args) {
method(new Test_interface() {
@Override
public void show() {
System.out.println("匿名内部类实现Test_interface接口");
}
});
}
public static void method(Test_interface ti) {// 实现类(匿名内部类)作为实参传递,多态,向上转型
ti.show();
}
}
|
匿名内部类修改接口/抽象类型作为返回值返回
Java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | // 接口
public interface Test_interface {
void show();
}
// 测试
public class Test {
public static void main(String[] args) {
Test_interface ti = method01();
}
public static Test_interface method01() {
return new Test_interface() {
@Override
public void show() {
System.out.println("匿名内部类实现Test_interface接口");
}
}; // 返回实现类(匿名内部类)对象,多态,向上转型
}
}
|