Java 内部类的四种实现方式
前言
今天的话我将为大家介绍Java的四种内部类,他们分别是普通内部类,静态内部类,局部内部类,匿名内部类。
提示:以下是本篇文章正文内容,下面案例可供参考
一、内部类是什么?
-
当一个类的定义出现在另外一个类的类体中时,那么这个类叫做内部类(Inner),而这个内部类所在的类叫做外部类(Outer)。
-
当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
二、内部类的分类
2.1 普通内部类
普通内部类-直接将一个类的定义放在另外一个类的类体中。(对象层级)
这种内部类的写法其实和外部类也基本是一致的。
普通内部类的特点:
- 普通内部类可以使用的关键字为:public,private,protected,final,abstract
- 普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
- 普通内部类需要使用外部类对象来创建对象。
- 如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字。
语法格式:
访问修饰符 class 外部类的类名{访问修饰符 class 内部类的类名{内部类的类体;}
}
案例:
package com.lagou.task03.generalClass;/*** @author 云梦归遥* @date 2021/11/22 16:18* @description*/
public class GeneralClass {private int cnt;public GeneralClass() {}public GeneralClass(int cnt) {setCnt(cnt);}public int getCnt() {return cnt;}public void setCnt(int cnt) {this.cnt = cnt;}public void show() {System.out.println("Outer class: " + getCnt());}// 创建第一种内部类:普通内部类public class InnerClass {private int cnt;public InnerClass() {}public InnerClass(int cnt) {setCnt(cnt);}public int getCnt() {return cnt;}public void setCnt(int cnt) {this.cnt = cnt;}public void show() {// 当内部类和外部类成员变量名相同时// 上面三种都是获取 内部类 成员变量的方法// 最后一种是获取 外部类 成员变量的方法System.out.println("Inner class: " + getCnt());System.out.println("Inner class: " + this.getCnt());System.out.println("Inner class: " + InnerClass.this.getCnt());System.out.println("Outer class: " + GeneralClass.this.getCnt()); // 使用 this 关键字}}
}
对应的测试类:
package com.lagou.task03.generalClass;/*** @author 云梦归遥* @date 2021/11/22 16:33* @description*/
public class GeneralClassTest {public static void main(String[] args) {GeneralClass generalClass = new GeneralClass(3);// 使用外部类对象 实例化 内部类对象GeneralClass.InnerClass innerClass = generalClass.new InnerClass(33);generalClass.show(); // Outer class: 3innerClass.show();// Inner class: 33//Inner class: 33//Inner class: 33//Outer class: 3}
}
运行结果:
2.2 静态内部类
静态内部类-使用static关键字修饰的内部类,隶属于类层级。(类层级)
语法格式:
访问修饰符 class 外部类的类名{访问修饰符 static class 内部类的类名{内部类的类体;}
}
静态内部类的特点:
- 静态内部类不能直接访问外部类的非静态成员。
- 静态内部类可以直接创建对象。
- 如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
静态内部类调用外部类中的成员变量:
- 第一种方式可以将静态外部类的类型写为static,然后在静态内部列使用 类名. 的形式引用
- 第二种方式可以在静态内部类中 new 对象,然后进行引用
案例:
package com.lagou.task03.staticClass;/*** @author 云梦归遥* @date 2021/11/22 16:41* @description*/
public class StaticClass {private static int cnt;private int cnt2;public StaticClass() {}public StaticClass(int cnt) {setCnt(cnt);}public static int getCnt() {return cnt;}public void setCnt(int cnt) {this.cnt = cnt;}public int getCnt2() {return cnt2;}public void setCnt2(int cnt2) {this.cnt2 = cnt2;}public void show() {System.out.println("Outer class: " + getCnt());}// 创建第二种内部类:静态内部类public static class InnerClass {private int cnt;public InnerClass() {}public InnerClass(int cnt) {setCnt(cnt);}public int getCnt() {return cnt;}public void setCnt(int cnt) {this.cnt = cnt;}public void show() {// 当内部类和外部类成员变量名相同时// 上面三种都是获取 内部类 成员变量的方法System.out.println("Inner class: " + getCnt());System.out.println("Inner class: " + this.getCnt());System.out.println("Inner class: " + InnerClass.this.getCnt());// 最后一种是获取 外部类 成员变量的方法,// 1.静态内部类中调用外部的变量必须也是静态的才行System.out.println("Outer class: 静态成员变量 " + StaticClass.getCnt());// 2.在静态内部类中 new 外部类的对象,然后进行引用StaticClass staticClass = new StaticClass();staticClass.setCnt2(555);System.out.println("Outer class: 非静态成员变量 " + staticClass.getCnt2());}}
}
对应的测试代码:
package com.lagou.task03.staticClass;/*** @author 云梦归遥* @date 2021/11/22 16:49* @description*/
public class StaticClassTest {public static void main(String[] args) {StaticClass staticClass = new StaticClass(5);StaticClass.InnerClass innerClass = new StaticClass.InnerClass(55);staticClass.show(); // Outer class: 5innerClass.show();// Inner class: 55//Inner class: 55//Inner class: 55//Outer class: 静态成员变量 5//Outer class: 非静态成员变量 555}
}
运行结果:
2.3 局部内部类
局部内部类-直接将一个类的定义放在方法体的内部时。(方法块层级)
语法格式:
访问修饰符 class 外部类的类名{访问修饰符 返回值类型 成员方法名(形参列表){class 内部类的类名{内部类的类体;}}
}
局部内部类的特点:
- 局部内部类只能在该方法的内部可以使用。
- 局部内部类可以在方法体内部直接创建对象。
- 局部内部类不能使用访问控制符和static关键字修饰符
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
案例:
package com.lagou.task03.areaClass;/*** @author 云梦归遥* @date 2021/11/22 16:58* @description*/
public class AreaClass {private int cnt;public AreaClass(int cnt) {setCnt(cnt);}public int getCnt() {return cnt;}public void setCnt(int cnt) {this.cnt = cnt;}public void show() {System.out.println("Outer class: " + getCnt());// 如果 内部类要使用 局部变量,为了保证数据的一致性,将局部变量设置为 final// 添加的原因:局部变量比局部内部类的作用范围更大,当局部内部类在使用时,会在底层从局部变量复制一份到局部内部类// 如果不使用final,当在局部内部类的外部修改这个变量的值以后,就会造成数据的不一致性final int snt = 6666;// 局部内部类不需要,也不能使用 访问控制符 和 static 进行修饰class InnerClass {private int cnt;public InnerClass() {}public InnerClass(int cnt) {this.cnt = cnt;}public int getCnt() {return cnt;}public void setCnt(int cnt) {this.cnt = cnt;}public void show() {System.out.println("Inner class: " + getCnt());System.out.println("snt : " + snt);}}InnerClass innerClass = new InnerClass(666);innerClass.show();}
}
对应的测试类:
package com.lagou.task03.areaClass;/*** @author 云梦归遥* @date 2021/11/22 17:06* @description*/
public class AreaClassTest {public static void main(String[] args) {AreaClass areaClass = new AreaClass(66);areaClass.show();// Outer class: 66//Inner class: 666//snt : 6666}
}
运行结果:
2.4 匿名内部类(最常用)
匿名内部类-就是指没有名字的内部类。
语法格式:
- 常规写法:
接口/父类类型 引用变量名= new 接口/父类类型() { 方法的重写};
- lambda写法(Java8之后的特性)
(参数列表) -> (方法体)
案例:
package com.lagou.task03.anonymousClass;/*** @author 云梦归遥* @date 2021/11/22 17:39* @description*/
public interface AnonymousInterface {public void show();
}
对应的测试类:
package com.lagou.task03.anonymousClass;/*** @author 云梦归遥* @date 2021/11/22 17:42* @description*/
public class AnonymousInterfaceTest {public static void main(String[] args) {// 第一种:匿名内部类,常规写法AnonymousInterface anonymousInterface = new AnonymousInterface() {@Overridepublic void show() {System.out.println("这是 匿名内部类 常规写法");}};anonymousInterface.show(); // 这是 匿名内部类 常规写法// 第二种:匿名内部类,lambda写法,更加简单(Java8)AnonymousInterface anonymousInterface1 = () -> System.out.println("这是 匿名内部类 lambda写法");anonymousInterface1.show(); // 这是 匿名内部类 lambda写法}
}
三,总结
以上就是Java的四种内部类的实现方式,相对来说,匿名内部类会更常用一些,而且匿名内部类如果使用lambda写法会更加的简洁。
好了,本期内容就到这里,谢谢大家。