什么是内部类?
内部类就是定义在类的内部的类,称之为内部类
Java中内部类分为以下4种:
- 成员内部类, 内部类在定义时没有使用static修饰(知晓)
- 静态内部类,内部类在定义时使用static修饰【Java中唯一可以使用static修饰类的方法】
(知晓)- 局部内部类,内部类在定义时定义在方法体内部(了解)
- 匿名内部类,它属于局部类类的特殊形态(必须会用)
内部类也是类,所以也会被JVM进行编译生成字节码文件【.class文件】
- 成员内部类生成字节码文件: 外部类类名$成员内部类类名.class
- 静态内部类生成字节码文件: 外部类类名$静态内部类类名.class
- 局部内部类生成字节码文件: 外部类类名$数字局部内部类类名.class
- 匿名内部类生成字节码文件: 外部类类名$数字.class
PS: 数字是从1开始逐渐递增【随着类的增加而增加】成员内部类(知晓)
成员内部类(知晓)
外部类可以使用权限修饰符为 public 和 默认的和abstract,成员内部类可以使用【4种权限修饰
符和abstract修饰】,可以将成员内部类看做就是在类中声明成员变量或成员方法,所以成员内
部类是属于对象的
//外部类
public class Outter {
//外部类中提供成员变量和方法、静态变量和方法
String name = "小白";
double PI = 3.14;
static int age = 10;
public static void showInfos(){
System.out.println("外部类静态方法");
}
public void display(){
System.out.println("外部类的成员方法");
//需要提供内部类对象创建,才可以使用成员内部类中所提供成员变量和成员方法
InnerClass innerClass = new InnerClass();
innerClass.name ="z";
innerClass.show();
}
//提供成员内部类 ---》 成员内部类就是定义在类中类,可以使用任何修饰符除static外
public class InnerClass{ //成员内部类
//可以在成员内部类中提供类的基础定义,但是不可以提供static修饰的属性和方法
//static double PI = 3.14;
String name = "小黑";
public void show(){
System.out.println("成员内部类中成员方法");
//如果说在成员内部类中调用与外部类同名属性
//this代表的是InnerClass对象,所以使用this.name
System.out.println(this.name);
//这种方式访问外部类的成员变量
System.out.println(Outter.this.name);
//调用外部类的成员方法【如果没有重名的效果,就不需要使用,外部类类名.this.方式调用】
display();
System.out.println(PI);
//成员内部类中是可以调用外部类静态属性和方法
System.out.println(age);
showInfos();
}
}
}
class Test{
public static void main(String[] args) {
//如何在外部创建成员内部类的对象
//成员内部类是属于外部类所有的,所以提供方式就是
// 外部类类名.内部类类名 内部类对象名 = new 外部类().new 成员内部类();
Outter.InnerClass innerClass = new Outter().new InnerClass();
innerClass.show();
}
}
总结: 成员内部类是定义在类中,不使用static修饰,可以使用4种权限修饰符,可以使用
abstract和final修饰,允许继承类与实现接口,成员内部类中不可以定义static修饰变量与方
法,成员内部类是可以直接访问外部类定义属性和方法,如果成员内部类出现了与外部类属性重
名,可以使用【this 和 外部类.this】进行区分,外部类要访问成员内部类的属性和行为时,提供
成员内类的对象
---》 外部类类名.内部类类名 内部类对象名 = new 外部类().new 内部类();
静态内部类(知晓)
静态内部类和成员内部类几乎与是一样的,唯一不点在于静态内部类使用static进行了修饰
PS:这是Java中类唯一可以使用static修饰的形式
//外部类
public class Outter {
//外部类中提供成员变量和方法、静态变量和方法
String name = "小白";
double PI = 3.14;
static int age = 10;
public static void showInfos(){
System.out.println("外部类静态方法");
}
public void display(){
System.out.println("外部类的成员方法");
//调用静态内部类中静态属性和方法 ---》 静态内部类类名.静态属性和静态方法即可
System.out.println(InnerClass.name);
//调用静态内部类中成员属性和方法 ---》 需要提供静态内部类的对象
new Outter.InnerClass().show();
}
//提供静态成员内部类 ---》 静态内部类就是定义在类中类,可以使用static修饰符修饰
public static class InnerClass{ //静态内部类
// 静态内部类可以提供普通类中所有可以提供操作【成员变量和方法、静态变脸和方法】
double PI = 3.15;
static String name = "小黑";
public void show(){
//在静态内部类中是不用担心 属性重名问题
//不是可以使用 外部类类名.this方法访问外部的属性【static中是不允许使用this和super关键字】
//只能在静态内部类中创建外部类对象,才可以访问外部类成员变量和成员方法
System.out.println(new Outter().name);
//调用外部类静态方法和静态属性 --> 外部类类名.静态属性或静态方法即可
System.out.println(Outter.age);
Outter.showInfos();
//静态内部类中的属性和方法直接调用即可
System.out.println(PI);
System.out.println(name);
}
}
}
class Test{
public static void main(String[] args) {
//提供静态内部类对象创建
//外部类类名.静态内部类类名 对象名 = new 外部类类名.静态内部类类名();
Outter.InnerClass innerClass = new Outter.InnerClass();
innerClass.show();
}
}
总结: 静态内部就是使用static修饰类【Java中只有这个类可以使用static修饰】,可以使用所
有权限修饰符,abstract和final修饰,静态内部类和静态属性和静态方法是一样都属于类,静态
内部类中是可以定义【成员变量和方法、静态变量和方法】,静态内部类中不允许明确访问方式
获取外部类this对象即【外部类类名.this】,所以在静态内部类中访问外部类成员变量和成员方
法,需要提供外部对象才可以,外部类静态变量和静态方法直接访问即可,如果有重名【外部类
类名.静态变量/静态方法】
静态内部类如果要创建对象
外部类类名.静态内部类类名 对象名 = new 外部类类名.静态内部类类名();
局部内部类(了解)
这个内部类不允许使用任何修饰符,只能定义在方法内部与局部变量是平级关系,访问作用域仅
限在方法的内部
//外部类
public class Outter {
//提供一个成员方法
public void show() {
//局部变量
final int age = 18;
//提供局部内部类【局部变量是平级关系】
class InnerClass {
//局部内部类中是不允许定义static修饰属性和方法
//允许提供成员变量和成员方法
String gender = "男";
public void display() {
//在局部内部类中访问方法中局部变量
/*
IDEA提供错误提示信息
Variable 'age' is accessed from within inner class, needs to be
final or effectively final
如果局部内部类使用方法提供的局部变量,这个局部变量必须是final修饰
*/
System.out.println(age);
}
}
//局部内部类只能在方法体的内部创建对象和使用,外界是无法访问到这个类中
new InnerClass().display();
//在此在方法体的内部修改成员变量
// age = 20;
}
}
为什么,局部内部类访问局部变量之后需要使用final声明?
final修饰局部变量的存储空间会发生改变,存储不再是栈中,而是方法区中常用池,局部变量就会
变成“引用”常量
局部内部类是声明在方法体内部,就会存在一个问题,局部内部类是随着方法而开始创建空间,
随着方法消亡开始回收空间,如果在方法内声明局部变量存储空间是栈【随着方法开始而创建随
着方法消亡会销毁】,如果局部内部类使用了这个局部变量,那么堆中地址就会和栈中位置产生
一个联系,堆中局部内部类就会引用到栈中局部变量,如果发生方法执行完毕,栈中空间空间会
进行立即回收,但是堆中局部内部类是不会被立即回收【GC机制】,就会出现堆栈存在一个“指
向空”引用,内报错了,所以使用final修饰符将局部变量修改为局部常量,将存储从栈中移动到方
法区中常量池,这样一来就算栈中空间被回收,但是方法区种空间还在,所以可以等待堆中局部
内部正常回收之后断练习,保证不会出现引用错误。
匿名内部类
/抽烟接口
public interface ISmoking {
/**
* 抽烟方法
* @param name 抽烟的名字
*/
void smoke(String name);
}
//按照以往的方法实现接口
public class Outter implements ISmoking {
@Override
public void smoke(String name) {
System.out.println("正在抽的烟是:"+name);
}
}
public class Test {
public static void main(String[] args) {
//调用抽烟方法展示抽象操作
//1.提供实现ISmoking接口对象
Outter outter = new Outter();
//2.通过outter对象调用smoke方法就可以执行抽烟操作
outter.smoke("华子");
//这个方法可以接收的对象必须是实现ISmoking接口的对象【利用就是面向兑现中多态】
showInfosSmokeName(outter);
//但是,如果当前实现接口类只使用一次,不在重复使用了,这样创建方式就比较繁琐也不利于管理
//所以Java就提供了一个更加便捷处理方式,提供匿名内部类作为接口的实现操作
/*
第一种 主要是针对与方法参数为接口类型进行赋值操作 --》完全匿名内部类
new 接口名(){
提供接口中抽象方法的实现;
}
*//*
第二种方式,针对匿名内部类所创建对象进行存储操作
接口名 对象名 = new 接口名(){
接口抽象方法的实现
}
*/
//smoking 存储的就是匿名内部类的引用【使用 new ISmoking的形式将后面的匿名内部类进行对象向上转型】
new ISmoking(){
@Override
public void smoke(String name) {
System.out.println("完全匿名内部类实现接口:"+name);
}
}.smoke("芙蓉王"); //这种形式主要是针对方法参数赋值使用的
//第二种 主要是针对于接口对象的赋值操作 --》局部匿名内部类
ISmoking smoking = new ISmoking() {
@Override
public void smoke(String name) {
System.out.println("使用匿名内部类创建了接口对象:"+name);
}
};
smoking.smoke("煊赫门");
//可以使用匿名内部类的这种语法便捷的对方法中参数进行赋值操作
showInfosSmokeName(new ISmoking() {
@Override
public void smoke(String name) {
System.out.println("匿名内部类对接口参数赋值:"+name);
}
});// 使用匿名内部类形式对接口参数进行赋值操作
}
//提供一个方法这个方法的参数类型是接口类型
public static void showInfosSmokeName(ISmoking smoking){
smoking.smoke("小熊猫");
}
}
标签:部类,java,内部,静态,成员,基础,static,public
From: https://www.cnblogs.com/blanset/p/16907344.html