目录
Java面向对象与权限修饰符、final关键字、代码块及内部类
权限修饰符
final关键字
代码块
非静态代码块
静态代码块
内部类
非静态成员内部类
静态成员内部类
局部内部类
定义与基本使用
接口类型/抽象类型作为方法参数传递和返回
匿名内部类
定义匿名内部类
匿名内部类基本使用
匿名内部类修改接口/抽象类型作为方法参数传递
匿名内部类修改接口/抽象类型作为返回值返回
在Java中,一共有4种访问修饰符,分别是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
修饰局部变量时表示不能二次赋值,但不代表变量未初始化时不可以赋值,例如下面的代码: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
修饰的代码块,写法如下:
{
// 语句
}
非静态代码块在对象中时,会优先于构造函数执行,并且有多少个对象就执行几次,例如下面的代码:
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
修饰的代码块即为静态代码块,写法如下:
static {
// 语句
}
静态代码块与非静态代码块一样,在类中时,创建对象会优先于构造方法执行,但是静态代码块只会在第一次创建对象时执行,例如下面的代码:
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
修饰时,称为非静态成员内部类,写法如下:
class 类名 {
// 成员
}
非静态成员内部类有以下的特点:
final
或abstract
修饰this.成员变量
,如果需要访问外部类的成员变量,需要使用外部类.this.外部类成员变量
注意,在JDK16之前,内部类成员(包括成员变量和成员方法)不可以是静态的,如果想要在IDEA中修改当前模块的JDK可以按照下面的方式进行:
File->Project Structure->Modules->选择需要改变JDK的模块->在Source页面改变Language Level为17->在Dependencies页面改变Module SDK(SDK即JDK)为17->OK
需要修改回JDK8重复上面的步骤,选择JDK8即可
改变项目JDK版本只需要在选择Module的位置选择Project即可
当需要创建非静态成员内部类对象时,按照下面的方法创建:
外部类.内部类 对象名 = new 外部类().new 内部类();
例如下面的代码:
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();
}
}
静态成员内部类和非静态成员内部类基本一致,不同的是:静态内部类不可以访问外部类中的非静态成员,创建静态成员内部类方式如下:
static class 类名 {
// 成员
}
创建静态成员内部类对象方式如下:
外部类.内部类 对象名 = new 外部类.内部类()
例如下面的代码:
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中,局部内部类可以理解为局部变量,定义在方法中或者代码块中,定义方式如下:
方法 {
class 类名 {
}
}
注意:局部内部类创建对象只能在内部类所在的外部类创建
例如下面的代码:
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();
}
}
下面的代码以接口类型为例,抽象类型基本一致
// 接口
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(); // 多态,向上转型
}
}
// 接口
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();
}
}
局部类实现如下:
// 接口
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(); // 返回实现类(局部内部类)的对象,多态,向上转型
}
}
匿名内部类,即没有类名的内部类,可以替换前面的接口/抽象实现类,此时创建出的内部类即为对应接口/抽象类的实现类,创建方式如下:
// 调用接口/抽象类重写后的方法
new 接口类名/抽象类名() {
// 重写抽象类/接口类方法
}.重写后的方法名();
接口类/抽象类名 对象名 = new 接口类名/抽象类名 {
// 重写抽象类/接口类方法
};
对象名.重写的方法名();
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();
}
}
// 接口
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();
}
}
// 接口
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接口");
}
}; // 返回实现类(匿名内部类)对象,多态,向上转型
}
}