毫无疑问, 内部类是定义在类内部的。也就是说, 它既是一个类, 也是一个类的成员。
为什么使用?
通常我们会在类中定义引用类型变量, 相当于借用其它类的功能来辅助本类的功能实现。 既然我们可以借用它类的实现, 为什么还要在类内部来定义一个类并且实现呢?
(1) 达到隐藏实现的效果, 避免其它实现依赖它(封装)。Wait!…在类的定义中, 也可以使用访问控制符来达到隐藏的效果啊, 例如default, protected. 通常我们单独的定义一个类, 是因为其它外部类(many)都要借助它来实现本类的功能.而内部类通常(当使用private修饰时)只是单独为本类(one)服务。
(2) 用于定制适于本类的成员. 通常情况下, 我们希望借助某个类来辅助我们功能的实现, 我们借助于它大部分的实现方法, 但是还要重写某些方法, 以到我们的需求, 也就是说该辅助类只适用于本类.And, 若其它的类继承本类时, 使用private修饰的内部类不会被继承, 我们对内部类的修改是安全的.
(3) 使代码更简洁:).
一、简介
通常我们定义一个类, 可以使用public, default(包访问) 修饰. 但是,
1.现在内部类作为一个类的成员, 可以使用public, protected, default, private修饰。
2.它本身是一个类, 也可以进行类的操作。 例如:继承, 实现接口, 定义新的变量。
3.它可以存在于类内部, 方法内(局部内部类)。
3.匿名内部类是特殊的。它没有类名, 因此没有构造器, 也就不涉及类名的修饰问题。
二、分类
非静态内部类
静态内部类
匿名内部类
三、非静态内部类
非静态内部类即不使用static修饰, 它最大的特点就是能够访问外部类的成员, 包括private。原因在于它持有外部对象的引用, So,在使用内部类的对象之前, 要先创建一个外部类的对象。
它是与实例相关的。
定义
访问控制符 类名(){
}
示例
例子1——定义与访问对象的变量
public class MyInner {
private int num = 5;
class Inner1 {
Inner1() {
System.out.println("I am inner 1");
//访问外部实例变量
System.out.println("outer class num param:" + num);
}
}
public static void main(String[] args) {
new MyInner().new Inner1(); //注意调用方式
}
}
// 输出:
I am inner 1
outer class num param:5
例子2——继承抽象类并实现方法
public class MyInner {
private int num = 5;
private abstract class changeNum {
void chang() {
}
}
private class ChangeSub extends changeNum {
void change() {
num = 100;
System.out.println("num is change:" + num);
}
}
public static void main(String[] args) {
new MyInner().new ChangeSub().change();
}
}
输出://
num is change:100
例子3——继承一个内部类
class Outer {
public Outer() {
}
class Inner {
void fun() {
}
}
}
public class MyInner {
private class Sub extends Outer.Inner {
public Sub(Outer outer) {
outer.super();——关键
}
public void fun() {
System.out.println("I am sub");
}
}
public static void main(String[] args) {
MyInner mi = new MyInner();
Sub sub = mi.new Sub(new Outer());
sub.fun();
}
}
虽然还没想到为何要继承一个内部类, 但是可以先通过该例子加深印象。
1. 注意声明的方式class Sub extends Outer.Inner
2. 注意public Sub(Outer outer) { outer.super(); }
这行代码。请记住, 生成一个非静态内部类对象需要依靠它的外部类对象。
调用父类的构造方法一般使用super()
.但是Sub的父类是Outer的内部类, 因此需要通过Outer的对象outer
来调用这个构造器outer.super();
.
四、静态内部类
静态内部类使用static修饰, 并不与实例相关, 不必通过外部类实例来调用本身的构造器.使用静态内部类也就意味着: 我不需要访问外部类的非static成员.
示例——注意与非静态内部类调用区别
public class MyInner {
private int num = 5;
private static int num2 = 50;
private static class StatiClass {
void change() {
System.out.println("num is not change:" + num2); // 假如改为num编译会报错
}
}
public static void main(String[] args) {
new StatiClass().change();
}
}
五、匿名内部类
匿名内部类不能直接在类里面定义(它都没名字!!!), 它存在于方法内或在代码行直接定义。它没有类名, 所以没有构造器, 可以在代码块进行初始化, 成员变量也可以在定义时就初始化。
定义——
new className(){
{
// initialize
}
methos and params
};
示例
例子1——实现接口或抽象类
// 定义接口和抽象类
interface Hi {
void sayHi();
}
abstract class Hello {
abstract void sayHello();
}
public class MyInner {
public static void main(String[] args) {
Hello hello1 = new Hello(){
public void sayHello(){
System.out.println("I smile and say hello");
}
};
hello1.sayHello();
Hi hi = new Hi() {
public void sayHi() {
System.out.println("I jump and say hi");
}
};
hi.sayHi();
}
}
例子2——获取普通类实例并且…
// 假设这个是调用方法, 且list只使用一次
private static void init(List list) {
}
普通版——
//before
ArrayList list = new ArrayList();
list.add("param1");
list.add("param2");
init(list);
升级版——
//now
init(new ArrayList() {
{
add("param1");
add("param2");
}
}
);
六、总结
何时使用内部类?
(1) 当这个类不被其它对象使用, 只服务于当前类.
(2) 在复杂业务的情况下, 可以通过多重继承(并非一次继承多个类)或者实现多个接口来满足要求。
使用何种内部类?
1.静态内部类或者非静态内部类?
(1) 考虑定义的内部类是对象相关还是类相关.
(2) 需要访问外部类的非静态成员时, 使用非静态内部类,。
(3) 在使用静态内部类和非静态内部类的都可以的情况下, 选非静态内部类。因为非静态内部类不持有外部类对象引用, 避免内存泄漏.
2.何时使用匿名内部类?
匿名内部类有些像是一次性餐具。 假如某个类作为参数只使用一次(只构建这一个对象), 后面都不会再使用了, 那么我们可以把它定义为匿名内部类。