一、基本概念

 1什么是内部类:

可以把一个类的定义放在另一个类的定义内部,这就是内部类。内部类作为外部类的一个成员,并且依附于外部类存在。一个类中可以存在多个内部类。内部类可以被protected,private,static修饰。内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类

特性:

  • 内部类仍然是一个独立的类,在编译之后会被编译成独立的.class文件。但是在前面冠以外部类类名和$符号。
  • 内部类不能以普通的形式访问。
  • 外部类不能直接访问内部类的的成员,但可以通过内部类对象来访问。
  • 内部类是外部类的一个成员,因此它可以自由访问外部类的成员变量,无论是否private。

链接到外部类:

当生成一个内部类对象时,次对象和它的外围类对象就存在一种联系,内部类会捕捉一个隐式引用,它引用了实例化内部对象的的外围类对象,使它可以访问外围类的全部状态。

public class Outer {private int i;class inner{void print(){new Outer().i=1;}}public static void main(String[] args) {inner inner = new Outer().new inner();}
}

 具体实现

 1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;3 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。

2、为什么要有内部类

  • 内部类是一种很有用的机制,它允许你把一些逻辑相关的类组织在一起,并控制内部类的可视性。
  • 内部类隐藏在外围类,并能与之通信,提供了一种进入外围类的窗口。
  • 每个内部类都能独立继承一个(接口)实现,无论外围类是否继承(接口)实现。这应该是内部类最吸引人的地方。

3、内部类的加载

      内部类的加载时延时加载,就是说使用时才会被加载,所以在实现单列是个很好的方式。

二、访问修饰符

首先,内部类是可以被private等修饰符修饰的。同时在访问也受到限制,

package page1;
public class Outer {public class inner1{}protected class inner2{}class inner3{}private class inner4{}
}//在同一个包下
package page1;
class OO{Outer.inner1 x1;       //public修饰,声明okOuter.inner2 x2;       //protected修饰,声明okOuter.inner3 x3;       //包访问修饰,声明ok// Outer.inner4 x4       //private修饰,不能声明public OO() {x1=new Outer().new inner1(); //可以创建对象x2=new Outer().new inner2(); //可以创建对象x3=new Outer().new inner3(); //可以创建对象}
}//不同包,但是继承了Outer
package page2;
import page1.Outer;
public class OO3 extends Outer {Outer.inner1 x1;         //public修饰,声明okOuter.inner2 x2;         //protected修饰,声明ok//Outer.inner3 x3;       //包访问修饰,不能声明// Outer.inner4 x4       //private修饰,不能声明public OO3() {x1=new Outer().new inner1();  //可以创建对象//x2=new Outer().new inner2(); //不可以创建对象}
}//不同包,没有继承Outer
package pake2;
import page1.Outer;
public class OO2 {Outer.inner1 x1;         //public修饰,声明ok//Outer.inner2 x2;       //protected修饰,不能声明//Outer.inner3 x3;       //包访问修饰,不能声明// Outer.inner4 x4       //private修饰,不能声明public OO2() {x1=new Outer().new inner1(); //可以创建对象}
}

总结:内部类在public修饰时,任何类都可以访问他,并创建出对象。

在protected修饰时,只有在同一个包下或者继承了外围类的类才能够声明,但是在创建内部类对象时,访问的默认构造函数,构造函数和类修饰符一样,OO3仅仅继承了Outer类,和内部类没有直接关系,访问拒绝。

 

三、内部类的继承

因为内部类的构造器必须连接到指向外围类对象的引用,所以那个指向外围类对象的引用必须被初始化。

public class Outer {public class inner1{}
}class OO4 extends Outer.inner1{public OO4(Outer s) {s.super();}
}

可以看到,oo4类仅仅继承与内部类,但是需要生成一个构造器,在传递一个指向外围类对象引用的同时,必须执行enclosingClassReference.super();

四、内部类重载

如果创建一个内部类,然后通过继承外围类并重新定义次内部类,内部类将会重载吗,其实只是外围类一个方法,并不起作用。

class Egg {private Yolk y;protected class Yolk {public Yolk() {System.out.println("Egg.Yolk()");}}public Egg() {System.out.println("New Egg()");y = new Yolk();}
}public class BigEgg extends Egg {public class Yolk {public Yolk() {System.out.println("BigEgg.Yolk()");}}public static void main(String[] args) {new BigEgg();}
}
复制代码
输出结果为:
New Egg()
Egg.Yolk()

在继承外围类是,内部类并没有什么变化,因为这是两个独立的实体,,但是可以明确继承耨个内部类。

public class Egg {protected class youk{public youk() {System.out.println("Egg.youk");}public void f(){System.out.println("Egg.youk.f");}}public Egg() {System.out.println("Egg");}private youk y=new youk();public void inser(youk yy){y=yy;}public void g(){y.f();}
}public class Egg2 extends Egg {class youk extends Egg.youk{public youk() {System.out.println("Egg2.youk");}public void f(){System.out.println("Egg2.youk.f");}}public Egg2() {inser(new youk());}public static void main(String[] args) {Egg e=new Egg2();e.g();}
}输出;
Egg.youk
Egg
Egg.youk
Egg2.youk
Egg2.youk.f

五、其他内部类

在之前看到的是内部类的典型用途,也就是平凡的内部类,但是内部类包含更多的语法用途。

  1局部内部类

在一个方法或者任意的作用域中定义内部类,称为局部内部类。局部内部类因为定义在方法或作用域,它不属于外围类的一部分,也不可以加访问修饰符,只能在定义内部类的方法里实例化,不能此方法外实例化。

如果你想创建一个类来解决某个问题,但又不希望该类是公共的,便可以使用到局部内部类。

interface A{
}
public class ll {public A a(){int i=1;    //必须final,jdk8默认可以省略不写class B implements A{//i=2; 因为为final无法赋值System.out.println(i);}return new B();}

局部内部类访问的局部变量必须final修饰,因为局部变量生命周期和方法一样,当方法弹栈,变量就消失,如果局部内部类对象还需要使用到该变量,就无法找到,final修饰使其进入常量池。

2、匿名内部类

匿名内部类就是一种没有用名字的内部类,属于局部内部类的一种特殊形式,如果说只会用到类的一个实例,类较小可以使用到。其本质就是是一个继承了该类或者实现了该接口的子类匿名对象。

interface A{
}
public class ll {public A a(){return new A() {};}
}

该实例中,创建一个A的匿名类对象,,通过new的表达式返回的引用被自动向上转型为A.

interface A{
}
public class ll {public A a( final int name){  //为finalreturn new A() {private int k=name;};}
}

在匿名内部类的使用到的参数必须final修饰,

在使用匿名内部类的原则

  • 匿名内部类不能有构造方法。
  • 匿名内部类不能定义任何静态成员、方法和类
  • 匿名内部类不能是public,protected,private,static。
  • 只能创建匿名内部类的一个实例。
  • 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
  • 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

3、静态内部类

在之前知道了内部类对象和它的外围类对象就存在一种联系,普通内部类隐式保存了一个指向外围类对象的引用,如果想要切断联系,可以将其使用static修饰。这样的类称为静态内部类。如果需要创建爱你静态内部类对象,就不在需要创建外围类的对象。

静态内部类和普通内部类的区别:

1静态内部类不持有外部类的引用,所以静态内部类只可以访问外部类的静态方法和静态属性

2静态内部类不依赖外部类 ,外部类消亡了,静态内部类还是可以存在的。

3普通内部类不能声明static的方法和变量 ,静态内部类可以包含他们。

接口中也可以定义内部类,内部类默认静态的。

java基础--内部类学习笔记相关推荐

  1. Java基础篇 学习笔记

    List item Java基础篇 学习笔记 java基础篇 第1章 计算机.程序和java概述 学习笔记 1.1什么是计算机 简单来说:计算机就是 ' 存储 ' 和 ' 处理 ' 数据的电子设备. ...

  2. Java基础知识学习笔记总结

    Java学习笔记总结 java基础复习 1. 抽象类可以有构造器,可以有一个非抽象的父类 2. 垃圾回收机制回收的是堆里面的内存,栈里面的数据自动入栈自动出栈 3. 引用类型的数据在堆当中,内存中操作 ...

  3. 狂神说java java基础篇 学习笔记

    java基础的视频内容笔记都在这了 前言等字数非常长的章节,使用了AI语音识别成文字后修改的,有错漏欢迎提出 面对对象模块的按照自己的理解进行了内容修改,可以对比原视频内容理解,如有建议欢迎提出 前言 ...

  4. Java基础提高学习笔记2

    Java基础加强笔记 11.Integer i1 = 13; Integer i1 = 13; 这两个是同一个对象 但赋值的值超过-128~127 就不是同一个对象 享元模式 flyweight 当这 ...

  5. Java基础提高学习笔记1

    Java基础加强笔记 03.开发时有两个阶段,编译时阶段 运行时阶段 工作间可以保存不同用户的不同配置 创建工作间需要关闭现有的工作间,并新建配置 每个类都有包.包要以公司的网址倒置加模块等等 int ...

  6. Java基础入门--学习笔记

    Java基础入门教程 itheima–java基础小白教程 学习配套软件:eclipse 1.基础知识 (1)常用DOS命令:切换盘–>E:,cd–>进入文件,可多级,cd - --> ...

  7. 内部类--毕向东Java基础教程学习笔记

    内部类的访问规则 1. 内部类可以直接访问外部类的成员,包括私有. 之所以可以直接访问外部类的成员,是因为内部类中持有外部类的引用,格式:外部类名.this 2.外部类要访问内部类,必须建立内部类对象 ...

  8. 【Java基础】学习笔记

    常见的java结构形式汇总 1.Hello,World!(基本形式) //类框架 public class Test{ //程序入口,主方法 这里的args代表的是一个变量名,可变.public st ...

  9. Java基础班学习笔记(8)

    1:如何制作帮助文档(了解) (1)写一个类 (2)加入文档注释 (3)通过javadoc工具生成即可 javadoc -d 目录 -author -version ArrayTool.java 如何 ...

最新文章

  1. 插入排序之——希尔排序(c/c++)
  2. vs2015 linux jni,使用Visual C++ 跨平台移动技术调试JNI Android 应用程序
  3. boost::hana::append用法的测试程序
  4. 永磁无刷电机及其驱动技术_扫盲——直流无刷电机知识
  5. Unity与Android交互
  6. php打印矩阵,PHP实现顺时针打印矩阵(螺旋矩阵)的方法示例
  7. 【Flink】报错 KryoException ConcurrentModificationException StackOverflowError
  8. Java判断平台为32位或64位,载入对应DLL
  9. Diskgenius硬盘处理软件
  10. aspose 转pdf表格大小乱了_关于Aspose.Words转PDF简体中文排版问题申明
  11. linux sqluldr2命令,sqluldr2 linux64
  12. RQNOJ 34 紧急援救
  13. 嵌入式linux 定时器
  14. 汽车汽配行业SaaS多租户系统助力车企打通行业壁垒,构建数字化管理平台
  15. win10同时安装wps和office时,如何设置默认应用为office!!!
  16. c语言做快速傅里叶变换和快速逆傅里叶变换
  17. 看了 Google 大神 Jeff Dean 的传说,我拜服了~
  18. (手机自适应)成人高考自考资讯网源码 织梦dedecms模板
  19. 解决屏蔽流氓蜘蛛抓取,如MJ12bot 、DotBot 、BLEXBot 、PetalBot 、DataForSeoBot
  20. linux禅道怎么改公司名字,在linux系统下一键部署禅道环境

热门文章

  1. 未能加载文件或程序集“System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”或它的某一个依
  2. 5种方法完美解决android软键盘挡住输入框方法详解
  3. Artetxe2018CoNLL_Uncovering divergent linguistic information in word embeddings...
  4. repeater 控件ajax绑定数据源,[Asp.net之旅]--数据绑定控件之Repeater
  5. chrome浏览器手机版怎么设置中文
  6. Cisco ASA防火墙实现IPSec 虚拟专用网,可跟做!!!
  7. Linux运维面试题-01
  8. javascript 标记_如何使用JavaScript更改Google Maps标记的颜色
  9. Linux命令(5):pwd
  10. STM32——MG90S数字舵机驱动