在类中再定义一个类,这个类就是内部类,内部类可分为成员内部类,局部内部类,匿名类
一、成员内部类
1、内部类的简介
在一个类中使用内部类,内部类是可以直接存储其所在类的私有成员变量。
成员内部类的写法:
public class OuterClass{//外部类
private class InnerClass{//内部类
//
}
}
在内部类中可以随意使用外部类的成员方法和变量(即使是private修饰),内部类的初始化也是使用new关键字。
package com.example.inner;
public class OuterClass {
/**
* 内部类
* @author Iverson_FL
*
*/
class innerClass{
innerClass(){//内部类构造方法
}
public void inf(){//内部类成员方法
}
int y = 0;//内部类成员变量
}
innerClass in = new innerClass();//在外部类中实例化内部类引用
public void outf(){
in.inf();//外部类调用内部类的方法
}
public innerClass doit(){//外部类方法,返回值为内部引用
//y = 4;//外部类不可以直接访问内部类的成员变量
in.y = 4;
return new innerClass();
}
public static void main(String[] args){
OuterClass out = new OuterClass();
//内部类的对象的实例化操作必须在外部类或外部类的非静态方法中实现
OuterClass.innerClass in = out.doit();
OuterClass.innerClass in2 = out.new innerClass();
}
}
内部类是可以随意访问外部类成员,但内部类的成员只有在内部类的范围内是可知的,不能被外部类使用,但是可以使用内部类对象引用调用成员变量。
内部类和外部类是可以交互使用彼此类中定义的变量的
2、内部类向上转型就是接口
如果将一个权限修饰符是private的内部类向上转型为其父类对象,或者向上转型为一个接口,在程序中就可以完全隐藏内部类的具体实现过程,可以在外部提供一个接口,在接口中声明方法,,如果在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类以不同的方式实现接口中的同一个方法,而在一般的类中是不能多次实现接口中的同一个方法的。
package com.example.inner;
interface OuterInterface {
public void f();
}
public class InterfaceInner {
public static void main(String[] args) {
OuterClass2 out = new OuterClass2();
OuterInterface outinner = out.doit();
outinner.f();
}
}
class OuterClass2 {
// 定义内部类实现OuterInterface接口
private class InnerClass implements OuterInterface {
InnerClass(String s) {// 内部类构造方法
System.out.println(s);
}
@Override
public void f() {// 实现接口的f方法
System.out.println("访问内部类的f方法");
}
}
public OuterInterface doit() {
return new InnerClass("访问内部类的构造方法");
}
}
运行结果:
由结果可以看出内部类InnerClass是private修饰的所以除了OuterClass2这个类能访问这个内部类之外是没有其他类可以访问的,也是因为InnerClass是private修饰的,所以不能访问f()方法,但是可以访问接口中f()方法
3、使用this关键字获取内部类和外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名是一样的,可以使用this关键字
package com.example.inner;
public class TheSameName {
private int x;
private class Inner {
private int x = 9;
public void doit(int x) {
x++;//调用形参x
this.x++;//调用内部类的变量x
TheSameName.this.x++;//调用外部类的变量x
}
}
}
(在内存中所有对象都被放置在堆中,方法以及方法中的形参或者局部变量放置在栈中)
二、局部内部类
内部类不仅可以再类中定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类
package com.example.inner;
interface OuterInterface2 {
}
public class OuterClass3 {
public OuterInterface2 doit(final String x) {
// 在doit中定义内部类
class InnerClass2 implements OuterInterface2 {
InnerClass2(String s) {
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
从上面的代码中可以发现内部类被定义在doit()方法的内部,在doit的方法中设置的参数是final型,如果需要在方法体重使用局部变量,该局部变量是需要被设置成final类型的。
三、匿名内部类
class OuterClass4{
public OutInterface2 doit(){
return new OutInterface2(){
private int i = 0;
public int getValue(){
return i;
}
}
}
}
在上面的例子中,return的类是没名字的,所以被称之为匿名内部类
内部类的语法是:
return new A(){
...//内部类体
}
四、静态内部类
在内部类前加入修饰符static就是静态内部类,一个静态内部类中是可以声明static成员的,但是在非静态内部类中是不可以声明静态成员的,同时静态内部类是不可以使用外部类的非静态成员的。主要有一下两个特点
1、如果创建静态内部类的对象,就不需要其他外部类的对象。
2、不能从静态内部类中访问非静态内部类的对象。
public class StaticInnerClass{
int x = 100;
static class Inner{
void doitInner(){
//System.out.println("外部类"+x);
}
}
}
上面的代码由于Inner是static型的,而外部类中的x不是static,所以是不可以使用的。
五、内部类的继承
public class OutPutInnerClass extends ClassA.ClassB{
public OutPutInnerClass(ClassA a){
a.super();
}
}
class ClassA{
class ClassB{
}
}
在某个类继承内部类的时候,必须硬性的给予这个类一个带参数的构造方法,并且该构造方法的参数为需要继承内部类的外部类的引用,同时在构造方法中使用a.super()语句