前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java学习之路:28.内部类(成员,局部,匿名,静态)以及继承

java学习之路:28.内部类(成员,局部,匿名,静态)以及继承

作者头像
花狗Fdog
发布2020-10-28 10:53:53
3650
发布2020-10-28 10:53:53
举报
文章被收录于专栏:花狗在Qt

如果在类中再定义一个类,则将在类中再定义的那个类称为内部类。

一.成员内部类

1.成员内部类介绍

在一个类中使用内部类,可以在内部类中直接获取其所在类的私有成员变量。 成员内部类的语法如下:

代码语言:javascript
复制
public class OuterClass{  // 外部类
    private class lnnerClass{  // 内部类
    // .......
    }
}

在内部类中可以随意使用外部类的成员方法以及成员变量。尽管这些类成员被修饰为private。

内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就好绑定在外部类对象上。内部类初始化方法与其他类初始化方法相同,都是使用new关键字。

代码语言:javascript
复制
public class OuterClass {
    innerClass in = new innerClass();  // 在外部类实例化内部类对象引用
    public void ouf() {
        in.inf();  // 在外部类方法中调用内部类方法
    }
    class innerClass {
        innerClass(){  // 内部类构造方法
    }
    public void inf() { // 内部类成员方法
    }
    int y = 0;   //定义内部类成员变量
    }
    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(); 
        // 实例化一个内部类对象
    }
}

在实例化内部类对象时,不能在new操作符之前使用外部类名称实例化内部类对象,而是应该使用外部类的对象来创建其内部类的对象。

内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。

2.内部类向上转型为接口

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

代码语言:javascript
复制
interface OutInterface{ // 定义一个接口
    public void fun(); 
}
public class InterfaceInner {
    public static void main(String[] args) {
        OuterClass2 out = new OuterClass2(); // 实例化一个OuterClass22对象
        // 调用doit()方法,返回一个OutInterface接口
        OutInterface outinter = out.doit(); 
        outinter.fun(); // 调用fun()方法
    }
}
class OuterClass2{
 // 定义一个内部类实现OutInterface接口
    private class InnerClass implements OutInterface{
        InnerClass(String s){ // 内部类构造方法
            System.out.println(s); 
        }
        public void fun() { // 实现接口中的fun()方法
            System.out.println("访问内部类中的fun()方法"); 
        }
    }
    public OutInterface doit() { // 定义一个方法,返回值类型为OutInterface接口
        return new InnerClass("访问内部类构造方法"); 
    }
}

运行结果:

在这里插入图片描述
在这里插入图片描述

OuterClass2类中定义了一个被修饰权限为private的内部类,这个内部类实现了OutInterface接口,然后修改doit()方法,使该方法返回一个OutInterface接口。由于内部类InnerClass修饰权限为private,所以除了OuterClass2类可以访问该内部类之外,其他类都不能访问,而可以访问doit()方法。由于该方法返回一个外部接口类型,这个接口可以作为外部使用的接口。它包含一个fun()方法,在继承此接口的内部类中实现了该方法,如果某个类继承了外部类,由于内部的权限不可以向下转型为内部类InnerClass,同时也不能访问fun()方法,但是却可以访问接口中的fun()方法。这样很好地继承该类的子类隐藏了实现细节,仅为编写子类的人留下一个接口和一个外部类,同时也可以调用fun()方法,但是fun()方法的具体实现过程却被很好地隐藏了,这就是内部类最基本的用途。

非内部类不能被声明为private或protected访问类型。

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

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

代码语言:javascript
复制
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
        }
    }
}

在类中,如果遇到内部类与外部类的成员变量重名的情况,可以使用this关键字进行处理。

二.局部内部类

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

代码语言:javascript
复制
interface OutInterface2{// 定义一个接口
}
class OuterClass3{
    public OutInterface2 doit(final String x){
    	// 在doit()方法中定义一个内部类
    	    class InnerClass2 implements OutInterface2{
    	        InnerClass2(String s){
    	            s = x; 
    	            System.out.println(s);
    	        }
    	    }
    	    return new InnerClass2("doit");
    }
}

三.匿名内部类

代码语言:javascript
复制
class OuterClass4{
    public OutInterface2 doit(){
        return new OutInterface2(){// 声明匿名内部类
            private int i = 0; 
            public int getValue(){
                return i; 
            }
        };
    }
}

在匿名内部类定义结束后,需要加分号标识,这个分号并不是代表定义内部类结束的标识,而是代表创建OutInterface2引用表达式的标识。 匿名内部类编译以后,会产生以“外部类$序号”为名称的.class文件,序号以1~n排列,分别代表1~n个匿名内部类。

四.静态内部类

在内部类前添加修饰符static,这个内部类就变为静态内部类了。一个静态内部类中可以声明static成员,但是在非静态内部类中不可以声明静态成员。静态内部类有一个最大的特点,就是不可以使用外部类的非静态成员。

代码语言:javascript
复制
public class StaticinnerClass{
    static class Inner{
    // .........
    }
}

五.内部类的继承

内部类和其他普通类一样可以被继承,但是继承内部类比继承普通类复杂,需要设置专门的语法来完成。

代码语言:javascript
复制
public class OutputInnerClass extends ClassA.ClassB{
    public OutputInnerClass(Class a){
        a.super();
    }
}
class CLassA{
    class ClassB{
    }
}

在某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法,并且该构造方法的参数为需要继续内部类的外部类的引用,同时在构造方法体中使用a.super()语句,这样才能为继承提供必要的对象引用。

若有错误,欢迎指正批评,欢迎评论。 每文一句:请相信,这个世界上真的有人在过着你想要的生活。也请明白,那些人大都曾隐忍过你尚未经历的挫折。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/03/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.成员内部类
    • 1.成员内部类介绍
      • 2.内部类向上转型为接口
        • 3.使用this关键字获取内部类与外部类的引用
        • 二.局部内部类
        • 三.匿名内部类
        • 四.静态内部类
        • 五.内部类的继承
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档