什么是 Java 内部类? {#什么是 Java 内部类}
在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。内部类也是 Java 类的五大成份之一;
Java 类的五大成份
- 成员变量
- 构造方法
- 成员方法
- 代码块
- 内部类
内部类优点 {#内部类优点}
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的
.class
文件,但是前面冠以外部类的类名和$
符号。 - 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
- 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。
- 内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限。
详细说明
- 外部类只有两种访问级别:public 和默认;内部类则有 4 种访问级别:public、protected、 private 和默认。
- 在外部类中可以直接通过内部类的类名访问内部类。
InnerClass ic = new InnerClass(); // InnerClass 为内部类的类名
- 在外部类以外的其他类中则需要通过内部类的完整类名访问内部类。
Test.InnerClass ti = newTest().new InnerClass(); // Test.innerClass 是内部类的完整类名
- 内部类与外部类不能重名。
提示:内部类的很多访问规则可以参考变量和方法。另外使用内部类可以使程序结构变得紧凑,但是却在一定程度上破坏了 Java 面向对象的思想。
内部类的使用场景 {#内部类的使用场景}
如一个事务内部还有一个独立的事务, 内部的事务脱离外部的事务无法独立使用
- 一个人必须有一个心脏
- 汽车里面有一个发动机
- 实现更好的封装性
内部类的分类 {#内部类的分类}
如果按照定义的位置来分类, 那么内部类分为以下四种
- 静态内部类:
类定义在了成员位置 (类中方法外称为成员位置,有 static 修饰的内部类)
- 实例内部类:
类定义在了成员位置 (类中方法外称为成员位置,无 static 修饰的内部类)
- 局部内部类: 类定义在方法内
- ** 匿名内部类:** 一般定义在方法中,或者可执行代码中。
静态内部类 {#静态内部类}
特点:
- 有
static
关键字修饰的内部类, 属于外部类本身的 - 静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。
- 静态内部类与其他类的用法完全一样, 只是访问格式需要加上
外部类. 内部类
案例代码
// 外部类
class Outer {
<span class="token comment">// 静态成员变量</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">String</span> sc_name <span class="token operator">=</span> <span class="token string">"墨白科技有限公司"</span><span class="token punctuation">;</span>
<span class="token comment">// 内部类</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Inner</span> <span class="token punctuation">{</span>
<span class="token comment">// 成员变量</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
<span class="token comment">// 构造器</span>
<span class="token keyword">public</span> <span class="token class-name">Inner</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">showName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 静态内部类可以直接访问外部类静态成员变量</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>sc_name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
// Test 方法`
`public` `class` `Demo3` `{`
`public` `static` `void` `main(String[]` args`)` `{`
`// 创建内部类对象 | 外部类. 内部类 变量 = new 外部类. 内部类构造器();`
`Outer.Inner` inner `=` `new` `Outer.Inner("墨白");`
inner`.showName();`
`}`
`}
实例内部类 {#实例内部类}
实例内部类特点
- 没有
static
修饰的内部类, 属于外部类对象的 - 宿主: 外部类对象
- 实例内部类不可以定义静态成员
- 实例内部类可以访问外部类的私有和静态成员
案例代码
// 外部类
class Outer2 {
<span class="token comment">// 实例内部类, 属于外部类对象的</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Inner2</span> <span class="token punctuation">{</span>
<span class="token comment">// 成员变量</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
<span class="token comment">// 实例内部类不能定义静态成员</span>
<span class="token comment">// private static String sc_name = "墨白科技有限公司"; // 报错</span>
<span class="token keyword">public</span> <span class="token class-name">Inner2</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">showName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
// Test 方法`
`public` `class` `Demo4` `{`
`public` `static` `void` `main(String[]` args`)` `{`
`// 宿主: 外部类对象`
`Outer2.Inner2` inner2 `=` `new` `Outer2().new` `Inner2("墨白");`
inner2`.showName();`
`}`
`}
局部内部类 {#局部内部类}
特点:
- 定义在方法中的类
- 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
- 局部内部类只在当前方法中有效。
- 局部内部类中不能定义 static 成员。
- 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
- 在局部内部类中可以访问外部类的所有成员。
- 在局部内部类中只可以访问当前方法中 final 类型的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用 .this. 的形式访问外部类中的成员。
案例代码
public class Test {
int a = 0;
int d = 0;
public void method() {
int b = 0;
final int c = 0;
final int d = 10;
// 局部内部类
class Inner {
a2 = a; // 访问外部类中的成员
// int b2 = b; // 编译出错
int c2 = c; // 访问方法中的成员
int d2 = d; // 访问方法中的成员
int d3 = Test.this.d; // 访问外部类中的成员
}
Inner i = new Inner();
System.out.println(i.d2); // 输出 10
System.out.printIn(i.d3); // 输出 0
}
public static void main(String[] args) {
Test t = new Test();
t.method();
}
}
匿名内部类 {#匿名内部类}
简介: {#简介}
匿名内部类 :是内部类的简化写法。匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类, 它的本质是一个
带具体实现的
父类或者父接口的
匿名的
子类对象。实际开发中,最常用到的内部类就是匿名内部类了。
特点 {#特点}
- 匿名类中允许使用非静态代码块进行成员初始化操作。
- 匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数。
- 匿名类的非静态代码块会在父类的构造方法之后被执行。
- 匿名内部类的本质作用是为了 简化代码。
案例说明: {#案例说明}
在没有学习匿名内部类之前, 我们需要使用接口时, 需要进行以下步骤:
- 定义子类
- 重写接口中的方法
- 创建子类对象
- 调用重写后的方法
// 定义一个接口
interface Swim {
// 抽象方法
public void swimming();
}
// 1. 定义接口的实现类
class Student implements Swim {
<span class="token comment">// 2. 重写抽象方法</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"蛙泳"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}
public` `class` `Demo5` `{`
`public` `static` `void` `main(String[]` args`)` `{`
`// 3. 创建实现类对象`
`Student` student `=` `new` `Student();`
`// 4. 使用对象调用方法`
student`.swimming();`
`}`
`}
可以看到实现的过程很麻烦, 而我最终的目的不过是想调用
swimming
方法而已, 所以下面可以使用匿名内部类来简化开发
匿名内部类前提和格式 {#匿名内部类前提和格式}
- 匿名内部类必须 继承一个父类 或者 实现一个父接口。
匿名内部类格式
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
使用方式 {#使用方式}
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 使用匿名内部类
new Swim() {
@Override
public void swimming() {
System.out.println("自由泳...");
}
}.swimming();
<span class="token comment">// 接口 变量 = new 实现类(); // 多态, 走子类的重写方法</span>
<span class="token class-name">Swim</span> s2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Swim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"蛙泳..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
s2<span class="token punctuation">.</span><span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
s2<span class="token punctuation">.</span><span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}
匿名内部类的使用场景 {#匿名内部类的使用场景}
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:
interface Swim {
public abstract void swimming();
}
public class Demo07 {
public static void main(String[] args) {
// 普通方式传入对象
// 创建实现类对象
Student s = new Student();
<span class="token function">goSwimming</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 匿名内部类使用场景: 作为方法参数传递</span>
<span class="token class-name">Swim</span> s3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Swim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"蝶泳..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">// 传入匿名内部类</span>
<span class="token function">goSwimming</span><span class="token punctuation">(</span>s3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 完美方案: 一步到位</span>
<span class="token function">goSwimming</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Swim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"大学生, 蛙泳..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">goSwimming</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Swim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"小学生, 自由泳..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 定义一个方法, 模拟请一些人去游泳</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">goSwimming</span><span class="token punctuation">(</span><span class="token class-name">Swim</span> s<span class="token punctuation">)</span> <span class="token punctuation">{</span>
s<span class="token punctuation">.</span><span class="token function">swimming</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}