Java中内部类

浅析Java中的内部类


一、内部类基础

Java中,将一个类定义在另一个类中或一个方法中,该类称为内部类;

内部类一般包括:成员内部类、局部内部类、匿名内部类、静态内部类;

1 成员内部类

1.1 一个类定义在另一个类的内部;


1.2 成员内部类可无条件访问外部类的所有成员变量/方法(包括private成员和静态成员);

class Circle {
    private double radius = 0;
    public static int count =1;
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
            System.out.println(count);   //外部类的静态成员
        }
    }
}

当成员内部类有何外部类同名的成员变量/方法时,会发生隐藏现象,即默认情况下访问成员内部类的成员;若要访问外部类的同名成员,则以如下形式访问:

外部类.this.成员变量/方法


1.3 外部类访问成员内部类,必须先创建一个成员内部类的对象,再通过指向该对象的引用进行访问;

class Circle {
    private double radius = 0;
    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问
    }
    private Draw getDrawInstance() {
        return new Draw();
    }
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
        }
    }
}


1.4 成员内部类是依附外部类存在的,即若创建成员内部类的对象,必须先创建一个外部类的对象,形式如下:

public class Test {
    public static void main(String[] args)  {
        //第一种方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建

        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
class Outter {
    private Inner inner = null;
    public Outter() {
    }
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
    class Inner {
        public Inner() { 
        }
    }
}


1.5 成员内部类可拥有private、包访问权限、proteccted、public;

若成员内部类使用private修饰,只能在外部类的内部访问;

若成员内部类使用public修饰,任何地方都能访问;

若成员内部类使用protected修饰,只能在同一个包下或继承外部类的情况下访问;

若成员内部类使用默认访问权限,只能在同一个包下访问;

注意:外部类只能使用public或默认访问权限修饰;


1.6 成员内部类的继承

a 成员内部类的引用方式Outter.Inner

b 构造器中必须有指向外部类对象的引用,并通过该引用调用super()

class WithInner {
    class Inner{
    }
}
class InheritInner extends WithInner.Inner { 
    // InheritInner() 是不能通过编译的,一定要加上形参
    InheritInner(WithInner wi) {
        wi.super(); //必须有这句调用
    }
    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner obj = new InheritInner(wi);
    }
}


2 局部内部类

2.1 定义在一个方法或一个作用域内部的类,与成员内部类的区别在于局部内部类的访问权限仅限于方法内或该作用域内;

class People{
    public People() {  
    }
}
class Man{
    public Man(){
    }
    public People getWoman(){
        class Woman extends People{   //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

2.2 局部内部类像方法中的一个局部变量,不能用public、protected、private、static修饰;

2.3 只能在局部内部类所在方法中创建局部内部类的对象;


3 匿名内部类

编写事件监听代码时使用匿名内部类不但方便,还易维护;

匿名内部类不能使用访问修饰符和static修饰符;

匿名内部类是唯一没有构造器的类,大部分匿名内部类用于接口回调;


4 静态内部类

定义在另一个类的内部,添加static关键字;

静态内部类不依赖外部类,且不能访问外部类的非static成员方法/变量,因为在没有外部类的对象情况下,可创建静态内部类的对象,若允许访问外部类的非static成员就会产生矛盾;

public class Test {
    public static void main(String[] args)  {
        Outter.Inner inner = new Outter.Inner();
    }
}
class Outter {
    public Outter() {
    }
    static class Inner {
        public Inner() {
        }
    }
}


二、深入理解内部类

1 为什么成员内部类可无条件访问外部类的成员?


2 为什么局部内部类和匿名内部类只能访问局部final变量?


3 静态内部类有特殊的地方吗?

静态内部类不依赖外部类,可在不创建外部类对象的情况下创建内部类的对象;


三、内部类的使用场景和好处?

1 每个内部类都能独立继承一个接口的实现,因此无论外部类是否已经继承某个(接口的)实现,对于内部类都没有影响;

2 方便将存在一定逻辑关系的类组织在一起,又可对外界隐藏;

3 方便编写事件驱动程序;

4 方便编写线程代码;


四、常见面试笔试题

1 根据注释填写(1), (2), (3)处代码

public class Test{
    public static void main(String[] args){
           // 初始化Bean1
           (1)
           bean1.I++;
           // 初始化Bean2
           (2)
           bean2.J++;
           //初始化Bean3
           (3)
           bean3.k++;
    }
    class Bean1{
           public int I = 0;
    }
    static class Bean2{
           public int J = 0;
    }
}
class Bean{
    class Bean3{
           public int k = 0;
    }
}

答案:

Test test = new Test(); Test.Bean1 bran1 = test.new Bean1();

Test.Bean2 bean2 = new Test.Bean2();

Bean bean = new Bean(); Bean.Bean3 bean3 = bean.new Bean3();

分析:

对于成员内部类,必须先产生外部类的实例化对象,再产生内部类的实例化对象;

对于静态内部类,不需产生外部类的实例化对象,可直接产生内部类的实例化对象;

创建静态内部类对象的一般形式为: 

外部类类名.内部类类名 xxx = new 外部类类名.内部类类名();

创建成员内部类对象的一般形式为: 

外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名();


2 下面这段代码的输出结果?

public class Test {
    public static void main(String[] args)  {
        Outter outter = new Outter();
        outter.new Inner().print();
    }
}
class Outter
{
    private int a = 1;
    class Inner {
        private int a = 2;
        public void print() {
            int a = 3;
            System.out.println(a);
            System.out.println(this.a);
            System.out.println(Outter.this.a);
        }
    }
}

输出:

3 2 1




注明:此文章是转载海子的博文,详情见:http://www.cnblogs.com/dolphin0520/p/3811445.html


Stkcd [股票代码] ShortName [股票简称] Accper [统计截止日期] Typrep [报表类型编码] Indcd [行业代码] Indnme [行业名称] Source [公告来源] F060101B [净利润现金净含量] F060101C [净利润现金净含量TTM] F060201B [营业收入现金含量] F060201C [营业收入现金含量TTM] F060301B [营业收入现金净含量] F060301C [营业收入现金净含量TTM] F060401B [营业利润现金净含量] F060401C [营业利润现金净含量TTM] F060901B [筹资活动债权人现金净流量] F060901C [筹资活动债权人现金净流量TTM] F061001B [筹资活动股东现金净流量] F061001C [筹资活动股东现金净流量TTM] F061201B [折旧摊销] F061201C [折旧摊销TTM] F061301B [公司现金流1] F061302B [公司现金流2] F061301C [公司现金流TTM1] F061302C [公司现金流TTM2] F061401B [股权现金流1] F061402B [股权现金流2] F061401C [股权现金流TTM1] F061402C [股权现金流TTM2] F061501B [公司自由现金流(原有)] F061601B [股权自由现金流(原有)] F061701B [全部现金回收率] F061801B [营运指数] F061901B [资本支出与折旧摊销比] F062001B [现金适合比率] F062101B [现金再投资比率] F062201B [现金满足投资比率] F062301B [股权自由现金流] F062401B [企业自由现金流] Indcd1 [行业代码1] Indnme1 [行业名称1] 季度数据,所有沪深北上市公司的 分别包含excel、dta数据文件格式及其说明,便于不同软件工具对数据的分析应用 数据来源:基于上市公司年报及公告数据整理,或相关证券交易所、各部委、省、市数据 数据范围:基于沪深北证上市公司 A股(主板、小企业板、创业板、科创板等)数据整理计算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值