一、内部类的作用
我们为什么需要内部类?或者说内部类为啥要存在?其主要原因有如下几点:
- 内部类方法可以访问该类定义所在作用域中的数据,包括被 private 修饰的私有数据
- 内部类可以对同一包中的其他类隐藏起来
- 内部类可以解决java 单继承的缺陷
- 当我们想要定义一个回调函数却不想写大量代码的时候我们可以选择使用匿名内部类来实现 举例说明如下:
- 可以无条件地访问外围类的所有元素
为什么可以引用:内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,内部类通过this访问外部类的成员
。
- 编译器自动为内部类添加一个成员变量,
这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;
- 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;
- 在
调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。
编译指令 javac classpath(.java文件的路径)
反编译指令 javap -v(详细信息) classpath(.class文件的路径)
/**
* 内部类无条件访问外部类元素
*/
public class DataOuterClass {
private String data = "外部类数据";
private class InnerClass {
public InnerClass() {
System.out.println(data);
}
}
public void getInner() {
new InnerClass();
}
public static void main(String[] args) {
DataOuterClass outerClass = new DataOuterClass();
outerClass.getInner();
}
}
输出:外部类数据
data这是在DataOuterClass定义的私有变量。这个变量在内部类中可以无条件地访问.
- 实现隐藏
关于内部类的第二个好处其实很显而易见,我们都知道外部类即普通的类不能使用 private protected 访问权限符来修饰的,而内部类则可以使用 private 和 protected 来修饰。
当我们使用 private 来修饰内部类的时候这个类就对外隐藏了。这看起来没什么作用,但是当内部类实现某个接口的时候,在进行向上转型,对外部来说,就完全隐藏了接口的实现了
接口
public interface InnerInterface {
void innerMethod();
}
具体类
/**
* 实现信息隐藏
*/
public class OuterClass {
/**
* private修饰内部类,实现信息隐藏
*/
private class InnerClass implements InnerInterface {
@Override
public void innerMethod() {
System.out.println("实现内部类隐藏");
}
}
public InnerInterface getInner() {
return new InnerClass();
}
}
调用程序
public class Test {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
InnerInterface inner = outerClass.getInner();
inner.innerMethod();
}
}‘
打印:实现内部类隐藏
从这段代码里面我只知道OuterClass的getInner()方法能返回一个InnerInterface接口实例但我并不知道这个实例是这么实现的。而且由于InnerClass是private的,所以我们如果不看代码的话根本看不到这个具体类的名字,所以说它可以很好的实现隐藏。
- 可以实现多重继承
我们知道 java 是不允许使用 extends 去继承多个类的。内部类的引入可以很好的解决这个事情。我的理解 Java只能继承一个类这个学过基本语法的人都知道,而在有内部类之前它的多重继承方式是用接口来实现的。但使用接口有时候有很多不方便的地方。比如我们实现一个接口就必须实现它里面的所有方法。而有了内部类就不一样了。它可以使我们的类继承多个具体类或抽象类。
如下面这个例子:
public class ExampleOne {
public String name() {
return "inner";
}
}
public class ExampleTwo {
public int age() {
return 25;
}
}
public class MainExample {
/**
* 内部类1继承ExampleOne
*/
private class InnerOne extends ExampleOne {
public String name() {
return super.name();
}
}
/**
* 内部类2继承ExampleTwo
*/
private class InnerTwo extends ExampleTwo {
public int age() {
return super.age();
}
}
public String name() {
return new InnerOne().name();
}
public int age() {
return new InnerTwo().age();
}
public static void main(String[] args) {
MainExample mi = new MainExample();
System.out.println("姓名:" + mi.name());
System.out.println("年龄:" + mi.age());
}
}
类三里面分别实现了两个内部类 InnerOne,和InnerTwo ,InnerOne类又继承了ExampleOne,InnerTwo继承了ExampleTwo,这样我们的类三MainExample就拥有了ExampleOne和ExampleTwo的方法和属性,也就间接地实现了多继承。
- 通过匿名内部类来优化简单的接口实现
创建线程的时候
二、内部类与外部类的关系
- 对于非静态内部类,内部类的创建依赖外部类的实例对象,在没有外部类实例之前是无法创建内部类的
- 内部类是一个相对独立的实体,与外部类不是is-a关系
- 创建内部类的时刻并不依赖于外部类的创建
对于普通内部类创建方法有两种:
public class ClassOuter {
public void fun(){
System.out.println("外部类方法");
}
public class InnerClass{
}
}
public class TestInnerClass {
public static void main(String[] args) {
//创建方式1
ClassOuter.InnerClass innerClass = new ClassOuter().new InnerClass();
//创建方式2
ClassOuter outer = new ClassOuter();
ClassOuter.InnerClass inner = outer.new InnerClass();
}
}
三、内部类的分类
内部类可以分为:静态内部类(嵌套类)和非静态内部类。非静态内部类又可以分为:成员内部类、方法内部类、匿名内部类。
- 静态内部类和非静态内部类的区别