【JavaSE8 基础 Keyword】class系列①之内部类与嵌入类总结 2019_8_7

静态嵌入类

基础

声明形式static class

嵌入类对象创建格式外部类类名.内部类类名 xx = new 外部类类名.内部类类名()

static作用声明C不是T的内部类,是外部顶级类,只是嵌入T中,被T单方面使用。

特性

  • 不存在顶级外部嵌入类
  • 只可在顶级外部类中(内部类中不可定义)、静态嵌入类中、接口中定义【不可定义在接口方法的default实现中,default实现只可使用局部内部类】

解析

官方解释

一个独立类C类嵌入在T类的类体中(单独拿出来写成C.java也是可以的)。正如T的静态方法中没有T的当前实例成员变量一样,C也没有T的当前实例,也没有任何词法封闭类的实例。

个人理解

  • 嵌入类只是精简了package结构,使用上与非内部类是一样的——访问T类实例成员变量需要创建实例对象
  • 本质区别——非静态的内部类在编译完成之后会隐式保存其外围类引用,指向外围类的实例。嵌入类没有。

特殊情况

① interface的成员类——是隐式的static静态嵌入类
② 类中的interface成员永远不是内部类

内部类

分类

①成员内部类(non-static 成员类)
②局部内部类(本地类)
③匿名内部类(匿名类)(也是局部内部类的一种,受到局部类规则的限制)

特性

三者共性

  • 内部类都不能显式、隐式声明static成员,除非该成员是静态常量变量,即static final变量
  • 内部类虽然不能声明static成员(除static final)但仍然可以继承外部类的非final变量的静态成员【我个人认为更准确的是可使用外部类的static成员,虽然自己不能声明】

An inner class may inherit static members that are not constant variables even though it cannot declare them.
——https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3

  • 内部类的类名不能与包含它的外部类同名
  • 深度内部类允许存在,当然深度static嵌入类也允许存在。

成员内部类特性

  • 可访问外部类的所有成员。

①成员内部类&&②局部内部类

  • 均可使用final修饰,也可使用访问修饰符PPPP
  • 均可以声明为abstract类,即二者可被顶级外部、内部类继承(局部类被继承有继承范围限制,只可在其局部范围内——只可能被同为局部内部类继承)

局部、匿名内部类特性

  • 二者均不能使用访问修饰符,但是局部类仍可显式继承类和实现接口,而匿名类被所创建的对象的类/接口限制——要么是一个类的子类,要么是一个接口的实现子类。
  • 静态环境下的局部类&匿名类(静态方法,静态初始化器,静态变量初始化表达式)不能使用外部类的实例成员变量,否则发生编译错误。但可引用局部类所处静态环境周围的局部变量但必须用final修饰。【同样适用于lambda表达式主体】
  • 局部内部类使用未在内部类中声明的任何外部函数的局部变量、形式参数或异常参数都必须声明为final或有效的final(4.12.4),并且需要在内部类主体前赋值,否则在尝试使用时将发生编译时错误。【原因:局部类、匿名类得到的是外部类、外围函数的局部变量的引用,而不是实际对象,故为了防止内部类获取到的引用值发生改变,必须使用final让该引用不可变。】
  • 匿名类内部不能定义任何构造函数、静态成员、静态方法和静态类,其他均可。是唯一无构造函数的类。
  • 匿名内部类为局部内部类的一种,所以局部内部类的所有限制同样对匿名内部类生效。

内部类访问外部类原理

实质

构建成员内部类实例对象的时候会从构造器传入一个指向外部类实例对象的引用。故此可以访问

实例

class Outer{
	class Inner{
	}
}

反编译后:public com.inbreeze.inner.Outer$Inner(com.inbreeze.inner.Outer);
虽然源码定义的内部类构造器是无参的,但在编译时,编译器会隐式声明添加一个参数,该参数的类型为指向外部类对象的一个引用,所以成员内部类中的 Outer this&0 指针便指向了外部类对象,因此可在成员内部类中随意访问外部类成员

实例详解

成员内部类

内部类对外部类成员访问没有任何限制。
内部类调用外部类实例变量及实例方法,不需new外部类实例。
注:内部类构造器被编辑器隐式声明外部类引用的参数,故内部类实例隐式持有外部类实例引用。

成员内部类访问外部类案例
//外部类
class Outer {
    private int id = 10;

    private void outerMehthod1() {
        //外部类调用内部类实例方法,需要this.new Inner()创建内部类实例
        Inner inner = this.new Inner();
        inner.innerMethod1();
        //可简写为:
        //this.new Inner().innerMethod1();
    }

    private void outerMehthod2() {
        System.out.println("OuterTest2......");
    }

    //内部类
    public class Inner {
        //内部类的id属性,不是外部类的id属性,也没有继承
        //Inner实例变量
        private int innerId = 100;
        private int outerId = Outer.this.id;
        //Inner实例方法
        public void innerMethod1() {
            System.out.println(Inner.this.innerId);
            //内部类调用外部类实例变量及实例方法,不需要new外部类实例
            //因为,外部类实例一定先于内部类实例创建
            //Inner实例依赖于Outer实例创建而创建
            System.out.println(Outer.this.id == outerId);
            Outer.this.outerMehthod2();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //创建外部类实例对象outer
        Outer outer = new Outer();
        //通过外部类实例.new 创建内部类实例inner
        Outer.Inner inner = outer.new Inner();
    }
}
成员内部类被外部类继承案例
class Outer {
    Outer(){
        System.out.println("Outer...");
    }
    class Inner{
        Inner(){
            System.out.println("Inner...");
        }
    }
}
class InheritInner extends Outer.Inner {

    // InheritInner() 无参构造不能通过编译
    //一定要加上被继承内部类的外部类实例形参
    InheritInner(Outer outer) {
        //必须调用,且是第一行
        outer.super();
       	System.out.println("InheritInner...")
        //解释:super与this调用者都是当前类,也就是InheritInner类
        //outer.super(); == outer.new Inner();
        //调用当前类InheritInner的父类Inner的构造函数,这个构造函数是outer内部类的构造函数
    }
    
	//psvm
    public static void main(String[] args) {
        Outer outer = new Outer();
        InheritInner obj = new InheritInner(outer);
    }
}
//console
Outer...
Inner...
InheritInner...

局部内部类

位置

在方法、初始化器、构造函数、字段初始化表达式中【static、non-static环境均可定义】

作用区域

不能跨{}使用,只有这个{}内部可以使用,继承。

static环境下局部类案例
//顶级外部类
public class Outer{
	//静态常量变量、静态变量
    static final int a3 = 0;
    static int a2 = 0;
    //实例变量
    int a1 = 0;
	
    //static函数,静态环境
    static void chineseStatic() {
    	//被内部类使用的外围局部变量 必须在局部内部类类体前赋值,定义清晰 
        final int i = 1;
        int b = 10;
        //static环境下的局部内部类
        class inner1 {
			//局部内部类不是顶级外部类,不能定义任何静态变量、静态方法、和静态嵌入类,其他的都可以
            //可拥有静态常量变量
            static final int i1 = 10;
            //内部类不能拥有static静态变量
            
            //局部内部类实例变量可被外部类、外围函数的局部变量赋值
            //【但不可改变外部类局部基本数据类型变量值,因为可用的都是final定义的】
            int i2 = i + b + i1 + 1 + a2 + a3;
            //内部类的实例函数
            public void say(){
                System.out.println(i2);
            }
        }
        inner1 inner1 = new inner1();
        inner1.say();
    }

匿名内部类

作用

继承某类或是实现某接口二者只能选一,并同时创建实例对象,可重写类、接口的原有函数,还可以写自己的(子类)实例方法、实例变量。
注:匿名内部类不能定义,任何静态变量、静态方法、和静态嵌入类及构造函数,其他都可以

位置

可以是传入的形式参数staticMethod1( new MyInterface(){ } );
可以是定义的普通对象MyClass1 myClass1 = new MyClass(){ };

实现接口继承类的匿名类实例
//接口
interface I1 {
    void test();
}

//类
class C1 {

}

public class Test {
    public static void main(String[] args) {
        //匿名的接口I1的完全实现类
        I1 i1 = new I1() {
            //只允许static final静态常量变量存在
            static final int a = 1;
            //自定义的实例变量
            int i = 10;

            //自定义的实例函数
            public void inherit() {
                System.out.println("MyMethod" + i);
            }

            @Override
            public void test() {
                System.out.println("InterfaceMethod...");
            }
        };
        i1.test();
        //匿名的类C1的子类
        C1 c1 = new C1() {
            //只允许static final静态常量变量存在
            static final int a = 1;
            //自定义的实例变量
            int i = 10;

            //自定义的实例函数
            public void say() {
                System.out.println("dddd" + i);
            }
        };
    }
}

使用场景

1.每个内部类都能独立的继承一个接口的实现,无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整。
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序、线程代码

参考博文

chenssy:java提高篇(十)-----详解匿名内部类
菜鸟教程:Java 内部类详解
The Java® Language Specification Java SE 8 Edition

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vc++全版本组件大全 VC++运行时(Visual C++ Runtime)是VC++开发环境中用于支持C和C++程序运行的基础库集合。这些库包含了执行C/C++程序所必需的基本函数和数据结构,例如内存管理、字符串操作、输入输出处理、异常处理等。VC++运行时库分为静态库和动态库两种形式,以适应不同类型的项目需求。 静态链接库 vs 动态链接库 静态链接库(Static Linking Libraries):在编译时,静态库的代码会被直接嵌入到最终生成的可执行文件中。这意味着每个使用静态库的程序都会包含库代码的一个副本,导致最终程序的体积较大,但不需要外部库文件支持即可独立运行。在VC++中,静态链接库的例子有LIBC.lib(用于单线程程序)和LIBCMT.lib(用于多线程程序)。 动态链接库(Dynamic Link Libraries):与静态链接相反,动态库的代码并不直接加入到应用程序中,而是在程序运行时被加载。这使得多个程序可以共享同一份库代码,节省了系统资源。VC++的动态运行时库主要通过msvcrt.dll(或其变体,如MSVCRTD.dll用于调试版本)实现,与之配套的导入库(Import Library)如CRTDLL.lib用于链接阶段。 运行时库的版本 VC++运行时库随着Visual Studio版本的更新而发展,每个版本都可能引入新的特性和优化,同时保持向后兼容性。例如,有VC++ 2005、2008、2010直至2019等多个版本的运行时库,每个版本都对应着特定的开发环境和Windows操作系统。 重要性 VC++运行时对于确保程序正确运行至关重要。当程序在没有安装相应运行时库的计算机上执行时,可能会遇到因缺失DLL文件(如MSVCP*.dll, VCRUNTIME*.dll等)而导致的错误。因此,开发完成后,通常需要分发相应的VC++ Redistributable Packages给最终用户安装,以确保程序能够在目标系统上顺利运行。 安装与部署 安装VC++运行时库通常是通过Microsoft提供的Redistributable Packages完成的,这是一个简单的过程,用户只需运行安装程序即可自动安装所需组件。对于开发者而言,了解和管理不同版本的运行时库对于确保应用程序的广泛兼容性和可靠性是必要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值