JavaSE 内部类

内部类

在类中再定义类称为内部类,内部类可以称为内部类,局部内部类以及匿名类

(1).成员内部类

一个类中使用内部类,可以在内部类中直接存取其所在类的私有变量。

public class OuterClass{
			private class InnerClass{
			}
}

内部类中可以随意使用外部类的成员方法以及成员变量,即使这些类成员被修饰为private
内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。

public class OutClass {   
    class innerClass{
        innerClass(){   //内部类构造方法
        }
        int x=0;    //内部类成员变量
        public void doit(){   //内部类方法
            System.out.println("内部类doit()方法");
        }
    }
    innerClass in=new innerClass();   //实例化一个内部类   
    public void outdoit(){     //外部类方法
        in.doit();         //调用内部类方法
      } 
    public innerClass inf(){  //外部类方法,返回值为内部类引用
       // x=1;   //外部类不能直接访问内部类的成员变量
        in.x=2;      //改变内部类的成员变量
        System.out.println(in.x);  //此时内部类的对象in的x成员变量已经被改变成2 
        return new innerClass();  //返回一个新的内部类引用,这个新对象的成员变量x为初始值0
    }

    public static void main(String[] args) {
        OutClass out=new OutClass();
        
     //!!!内部类对象实例化操作必须在外部类或外部类的非静态方法中实现!!!!
        
        OutClass.innerClass in=out.inf();  //通过外部类对象的inf方法的返回值创建一个新的对象
        OutClass.innerClass in2=out.new innerClass();//在外部类中实例化操作
        //innerClass in3=new innerClass();  编译报错
        innerClass in4=out.new innerClass();  
        in2.doit();
        System.out.println(in.x);
        out.outdoit();   //调用外部类的方法
    }
}

输出结果:
2
内部类doit()方法
0
内部类doit()方法

内部类对象和外部类对象关系非常紧密,内外可以交互使用彼此类中定义的变量。只不过外部类调用内部类的变量需要通过内部类的对象。
如果在外部类和非静态方法之外实例化内部类对象,需要使用外部类,比如上面的main函数是个static方法。 实例化一个内部类需要OutClass.innerClass in=out.new innerClass(); 应该使用外部类对象来创建内部类对象
内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。

(2)内部类向上转型为接口

如果将一个权限修饰符为private的内部类向上转型为其父类对象,或者直接向上为一个接口,在程序中就可以完全隐藏内部类的具体实现过程。可以在外部提供一个接口,在接口中声明一个方法。在实现该接口的内部类中实现该方法(也就是重写方法),就可以定义多个内部类以不同的方式实现接口同一个方法,而在一般类中是不能多吃实现接口中的同一个方法的,这种技巧经常被应用在Swing编程中,可以在一个类中做出多个不同的响应事件

interface OutInterFace{   //定义一个接口
     public void f();
}

public class InterfaceInclass{  
    public static void main(String[] args) {
        OutClass out=new OutClass();   //实例化一个OutClass对象
        OutInterFace outinter=out.doit();    //调用doit()方法,返回一个OutInterFace接口
        outinter.f();   //调用f()方法
    }
}
 class OutClass {   //实现一个内部类实现OutInterFace接口
     private class InnerClass implements  OutInterFace{
            InnerClass(String s){  //内部类的构造方法
                System.out.println(s);
            }
         @Override
         public void f() {    //内部类方法
             System.out.println("访问内部类中的f()");
         }
     }
     public OutInterFace doit(){
         return new InnerClass("访问内部类的构造方法");
     }
}
输出接口:
访问内部类的构造方法
访问内部类中的f()

OutClass类中定义了一个修饰权限为private的内部类,所以除了OutClass类之外任何类都不能去调用内部类,这个内部类实现了OutInterFace()接口,还重写了接口的f()方法。OutClass类中定义了一个doit()方法,返回一个OutInterFace()接口。外部类不能访问内部类,但是可以访问这个doit()方法。由于该方法返回一个外部接口类型,这个接口可以作为外部全部使用的接口。它包含一个f()方法,在继承该接口的内部类中实现(重写)了该方法。如果某个类继承了外部类OutClass,由于内部权限不可以向下转型为内部类InnerClass,同时也不能访问f()方法,但是可以访问接口的f()方法。
outinter.f()通过接口访问f()方法,很好地对继承该类的子类隐藏了实现细节,仅为编写子类的人留下一个接口和一个外部类,同时也可以调用f()方法,但是f()方法的具体实现过程却很好地被隐藏了。

(3)使用this关键字获取内部类与外部类的引用

如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字


public class UseThis {
    private int x;
    private class Inner{
        private int x=11;
        public void doit(int x){
            x++;      //形参x++
            System.out.println("形参x++后:"+x);
            this.x++;   //内部类x++
            UseThis.this.x++;   //外部类x++;
            //UseThis.x++  报错
        }
    }

    public static void main(String[] args) {
        UseThis u=new UseThis();
        Inner inner=u.new Inner(); //在外部类中实例化一个内部类
        inner.doit(1);
        System.out.println(u.x);
        System.out.println(inner.x);
    }
}

输出结果:
形参x:2
1
12

遇到内部类和外部类的成员变量重名的情况可以使用this关键字处理
外部类名称后跟一个点操作符和this操作符可以获取一个外部类的一个引用

(2)局部内部类

内部类不仅可以在类中定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类

interface InterFace2{

}
public class OutClass2{
    public static void main(String[] args) {
        OutClass3 out=new OutClass3();
        out.doit("方法形参doit");
    }
}
class OutClass3 {
    public InterFace2  doit(final String x){   //形参设为final
        class InnerClass2 implements InterFace2{
            InnerClass2(String s) {
                s=x;
                System.out.println(s);
            }
        }
        return new InnerClass2("doit");
    }
}

输出结果:
方法形参doit

内部类定义在doit()方法内部。所以在doit()外部不能访问内部类,但是该内部类可以访问当前代码块的常量以及此外部类的所有成员。
如果内部类需要在方法体中该局部变量,该局部变量需要设为final.使内部类不会改变该局部变量的值

(3)匿名内部类

匿名内部类的含义:定义子类,实现接口,创建子类对象一步完成

new 接口或父类(){
			重写抽象方法
};
package com.lzw;
interface InterFace2{

}
public class OutClass2{
    public static void main(String[] args) {
        OutClass4 out=new OutClass4();
        InterFace2 in=out.doit();
        System.out.println(out.doit());
    }
}
class OutClass4{
      public  InterFace2 doit(){     //实现接口
            return new InterFace2() {   //匿名内部类
                private int i=0;
                public int getValue(){
                    return i;
                }
            };
      }
}
输出结果:
com.lzw.OutClass4$1@16d3586

匿名内部类没有名称,所以匿名内部类使用默认构造方法来产生对象。内部类定义结束后需要加分号,代表引用表达式的创建。
匿名内部类在编译后会产生"内部类名$序号"为名称的.class文件,序号以1 ~ n排列,代表1~n个匿名内部类

匿名内部类成员方法的调用

public class OutClass2{
    public static void main(String[] args) {
        OutClass4 out=new OutClass4();
        System.out.println(out.doit());
    }
}
class OutClass4{
      public  int doit(){
            return new InterFace2() {   //匿名内部类
                private int i=0;
                public int getValue(){
                    return i;
                }
            }.getValue();   //调用内部类的成员方法
      }
}
输出结果:
0

匿名内部类只能写到方法中

(4)静态内部类

在内部类前添加修饰符static,这个内部类就成为静态内部类。
一个静态内部类中可以声明static成员,但是在非静态内部类中不可以声明静态成员。
静态内部类不可以使用外部类的非静态成员,静态内部类在程序开发中比较少见。

public class OutClass2{
    int x=100;
    static int y=11;
    static class Inner {    //定义内部类
        void doit() {
            System.out.println("外部类x:"+x);   //编译报错  
             System.out.println("外部类y:"+y);
        }
    }
    public static void main(String[] args) {
        OutClass2 out=new OutClass2();
        Inner in=new Inner();    //静态内部类对象的创建不需要其他外部类的对象
        //也就是不需要普通内部类对象创建的,Inner in=out.new Inner();
        in.doit();
    }
}
输出结果:
外部类y:11

创建静态内部类对象不需要其他外部类对象
不能从静态内部类对象中访问非静态外部类对象

进行软件测试时,如果在每个java文件中都设置一个主方法,将会出现很多额外代码,而程序不需要这些主方法,可以在静态内部类中定义主方法。

public class OutClass2{
    int x=100;
    static int y=11;
    static class Inner {    //定义内部类
        void doit() {
            System.out.println("外部类x:"+x);   //编译报错  
             System.out.println("外部类y:"+y);
        }
        public static void main(String[] args) {
            System.out.println("静态内部类主方法");
        }
    }
}
输出结果:
静态内部类主方法
(5)内部类的继承

内部类继承要设立专门的方法

public class father {
    public father(){
        System.out.println("外部类father");
    }
    class Son{
		int x=0;
        void doit(){
            System.out.println("内部类son");
        }
    }
}
public class OutClass2 extends father.Son{
    int x=100;
    static int y=11;
    public OutClass2(father f){
        f.super();
        super.doit();    //使用父类的方法
        System.out.println(super.x);   //输出父类的成员变量
    }
    void doit(){     //重写doit()方法
        System.out.println("outclass类");
    }
    public static void main(String[] args) {
        OutClass2 out = new OutClass2(new father());
    }
}
输出结果:
外部类father
内部类son
0

在某个类继承内部类时,必须让这个类一个带参数的构造方法,并且该构造方法的参数是需要继承内部类的外部类的引用,同时在构造方法体中是用参数对象名.super()语句

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值