目录

非静态内部类

静态内部类

使用内部类

局部内部类

匿名内部类


【内部类是什么?】

内部类 —— 就是把一个类放在类里面定义

内部类 - 寄生类

外部类 - 宿主类

内部类,由于踏上一级程序单元是类,因此他完全可以使用 private | protected | 默认 | public 这四个访问控制符

由于内部的上一级程序单元是类,可以用 static 修饰。有 static 修饰的类属于外部类本身;没有 static 修饰的类属于外部类的实例。

【为什么要引入内部类?】

  1. 为了更好地封装,可以把内部类隐藏在外部类中,不允许同一个包内其他类来访该类(在该类内有效,在其他类无用处)
  2. 内部类成员可以直接访问外部类的私有数据
  3. 匿名内部类适合用于创建那些仅需要使用一次的类

【注意】非静态外部类不能拥有静态内部类。(为什么?)【注释4】

【如何使用内部类?】

非静态内部类

内部类有一个好处:他可以直接访问外部类的 private 成员(field/方法/构造器);反过来,外部类不能访问内部类成员

  • 若是没有 static 修饰的内部类的实例,必须寄生在“外部类”的对象里。
  • 若有 static 修饰的内部类的实例,寄生在“外部类”的类本身里

以下代码表明。调用寄生实例方法之前,必须创建宿主实例

/** * @ClassName: Cow* @description: * @author:FFIDEAL* @Date: 2020年2月27日22:30:24*/  public class Cow {private double weight;public Cow() {}public Cow(double weight) {this.weight = weight;}// 定义一个非静态内部类private class CowLeg {// 定义两个非静态类实例private double length;private String color;public CowLeg() {}public CowLeg(double length, String color) {this.length = length;this.color = color;}public double getLength() {return length;}public void setLength(double length) {this.length = length;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}// 创建非静态内部类的实例方法public void info() {System.out.println("当前牛腿的颜色是" + color + ",牛腿的长度为" + length);// 可以调用当前外部类的private修饰的成员变量System.out.println("当前牛的体重是:" + weight);}}// 在非静态内部类中,要创建内部类的实例,首先要创建宿主实例public void test() {CowLeg c1 = new CowLeg(1.12, "黄色");c1.info();}public static void main(String[] args) {Cow cow = new Cow(112.6);cow.test();}
}

非静态内部类,也属于非静态成员 —— 因为不能被外部静态成员所访问

【若查找某个变量时】

当在非静态内部类的方法访问某个变量时:在该方法内查找 -> 在方法所在类中查找 -> 在该类的外部类查找 ->系统出现编译错误

/** * @ClassName: DiscernVariable* @description: 描述内部类调用外部类成员变量、内部类成员变量和局部成员变量时的语句* @author: FFIDEAL* @Date: 2020年2月27日 下午10:37:29*//*** @author dell**/
public class DiscernVariable {private String prop = "我在早上学习Java!";// 创建内部类private class InClass {private String prop = "我在中午学习Java!";// 创建内部类的一个测试方法public void info() {String prop = "我在晚上学习Java!";// 通过外部类名.this.varName访问外部类实例变量System.out.println("外部类的实例变量值为" + DiscernVariable.this.prop);// 通过this.varName访问外部类实例变量System.out.println("内部类的实例变量值为" + this.prop);// 直接访问局部变量System.out.println("局部变量值为" + prop);}}// 创建一个方法用于创建内部类的实例public void test() {InClass ic = new InClass();ic.info();}// 创建一个宿主实例,用宿主实例调用上述方法public static void main(String[] args) {DiscernVariable dv = new DiscernVariable();dv.test();}
}

【注意】在非静态内部类中,所有的方法、成员变量都属于实例的。所以在创建内部实例之前,若没有外部类,则无法获得外部宿主实例。反之,在static修饰的内部类中,在运行时,已经加载了外部类,存在了宿主类,就可以创建内部静态类的对象,该对象寄生在外部类中

静态内部类

静态内部类有 static 修饰,寄生在“外部类”的类本身里,而不属于任何外部类的实例。静态内部类可以包含静态成员,也可以包含非静态成员。但是静态内部类的实例方法,也是属于静态成员,因此他不能访问外部类的非静态成员。

  • 以上为什么不能用类名调用?【注释5】
/** * @ClassName: StaticInnerClassTest* @description:静态内部类的实例方法也不能访问外部类的实例方法,只能访问外部类的静态成员* @author: FFIDEAL* @Date: 2020年2月27日 下午11:02:48*/public class StaticInnerClassTest {private String str1 = "这是非静态字符串";private static String str2 = "这是静态字符串";static class StaticInnerClass {// 静态内部类可以包含静态成员private static int age;public void access() {// System.out.println(str1);代码错误。静态内部类不能访问外部类的非静态成员变量System.out.println(str2);}}public static void main(String[] args) {new StaticInnerClass().access();}
}

使用内部类

  1. 定义变量
  2. 创建实例
  3. 访问它的类 field/类方法

【在外部类以内使用内部类】

若在外部类的里面,使用内部类。并没有太多需要注意的地方。只需要指导不要在外部类的静态成员中使用非静态外部类,因为静态成员不能访问非静态成员。

【在外部类以外使用非静态内部类】

  1. 声明变量:外部类.内部类 变量名
  2. 创建非静态内部类的实例:在此之前,必须先创建外部类的实例 —— 必须先创建宿主。接下来用“宿主.new 外部类构造器()”
  3. 非静态内部类派生子类:由于子类的构造器,必须调用父类的构造器一次,因此必须在子类构造器中使用宿主对象去调用非静态内部类的构造器
/** * @ClassName: CreateInnerInstance* @description: 在外部类以外使用非静态内部类* @author: FFIDEAL* @Date: 2020年2月29日 下午1:00:46*/class Out{//创建一个非静态内部类class In{public In(String msg) {System.out.println("调用一个内部类构造器,传进的参数是:"+msg);}}
}
public class CreateInnerInstance {public static void main(String[] args) {Out.In in = new Out().new In("在学习Java的时候不要忘记学习Java虚拟机");/*Out类中的in类,先new一个Out类的对象,在new一个In的对象,这样就有宿主了* 相当于* 使用OutClass.InnerClass的形式调用内部类变量* Out.In in;* 创建外部类宿主对象* Out out = new Out();* 通过外部类实例和new来调用内部类构造器创建非静态内部类实例* in = out.new In("在学习Java的时候不要忘记学习Java虚拟机");*/}
}

【在外部类以外使用非静态内部类】

  1. 静态内部类它是寄生外部类的类本身里面的,所以一般不需要程序员去理会宿主,可以把外部类当做静态内部类的包就行了。只需要外部类就可以调用构造器了。
/** * @ClassName: CreateStaticInnerClassTest* @description: 测试在外部类以外使用静态内部类* @author: FFIDEAL* @Date: 2020年2月29日 下午1:17:32*/class StaticOut{//创建一个静态内部类static class StaticInner{public StaticInner() {System.out.println("静态内部类构造器");}}
}public class CreateStaticInnerClassTest {public static void main(String[] args) {new StaticOut.StaticInner();}
}

局部内部类

局部内部类是一个局部成员,和局部变量相似,因此不能用 static 、访问控制符修饰。局部内部类用 final 修饰是可以的,辨明该局部内部类不能被继承。局部内部类的作用域实在是太有限了 —— 除了方法就不能使用了。由于局部内部类只能在当前方法中使用,因此使用起来比较简单。局部内部类的class名为:外部类$N个内部类.class(为什么要有N)【见注释1】

匿名内部类

它是没有名字的内部类,所以程序以后无法再访问这个“匿名内部类”。当程序创建匿名内部类时,会立即创建匿名内部类的实例。

//匿名内部类的语法new 接口() | 父类构造器(参数){//类主体
}// —— 上述语法格式实际上返回匿名内部类的实例。程序以后只能使用匿名内部类的实例
/** * @ClassName: AnonymousTest* @description: 实现接口来创建内部类:new 实现接口* @author: FFIDEAL* @Date: 2020年2月29日 下午2:33:10*/interface Products{public double getPrice();public String getName();
}public class AnonymousTest {//需要传入一个Product实例public void test(Products p) {System.out.println("购买一个"+p.getName()+",话费了"+p.getPrice());}public static void main(String[] args) {AnonymousTest at = new AnonymousTest();at.test(new Products() {public double getPrice() {return 5560;}public String getName(){return "华为手机";}});}
}
/** * @ClassName: AnonymousInner* @description: 继承父类创建内部类:new 实现接口,匿名内部类将拥有和父类相似的构造器* @author: FFIDEAL* @Date: 2020年2月29日 下午6:30:06*/
abstract class Device{private String name;public abstract double getPrice();public Device() {}public Device(String name) {this.name = name;}public void setName(String name) {this.name = name;}public String getName() {return name;}}public class AnonymousInner {public void test(Device d) {System.out.println("又买了一个"+d.getName()+",花掉了"+d.getPrice());}public static void main(String[] args) {AnonymousInner ai = new AnonymousInner();//调用有参数的构造器创建Device的匿名类实例对象ai.test(new Device("示波器"){public double getPrice() {return 55.6;}});//调用无参数的构造器Device d = new Device() {//初始化块{System.out.println("匿名内部类的初始化块");}//实现抽象方法public double getPrice() {return 56.2;}//重写父类的方法public String getName() {return "键盘";}};ai.test(d);}
}

【匿名内部类的规则】

  1. 匿名内部类必须显式继承一个父类,或实现【一个】接口
  2. 匿名内部类必须实现接口或抽象类中所有抽象方法(为什么?)【见注释2】
  3. 匿名内部类不能有构造器 (为什么?)【见注释3】

【注释1】因为一个外部类,不同方法中可以定义多个同名的局部内部类

【注释2】因为匿名内部类需要立即创建市里,因此他不能是抽象的

【注释3】因为匿名内部类没有名字,构造器名字不能确定

【注释4】首先静态成员不能访问非静态成员。若静态内部类位于非静态外部类之内,那么静态内部类不能访问外部类,且那就失去了静态内部类存在的意义。

【注释5】因为类中的static是属于类本身的。但是static修饰类就与里面非static修饰的方法无关。该方法依然是非静态方法。静态内部类属于外部类而已。非静态内部类属于内部类实例。但创建这个内部类实例之前,要确保有外部类的实例这个宿主存在

【Java】6.7 内部类相关推荐

  1. java 为什么有匿名类_全面了解Java中的内部类和匿名类

    Java内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了 ...

  2. Java学习笔记二十:Java中的内部类

    Java中的内部类 一:什么是内部类: (1).什么是内部类呢? 内部类( Inner Class )就是定义在另外一个类里面的类.与之对应,包含内部类的类被称为外部类. (2).那为什么要将一个类定 ...

  3. Java Inner Class 内部类

    内部类  Inner Class 一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分. Java中的内部类共分为四种: 静态内部类static inner class ( ...

  4. Java核心类库——内部类那点事儿

    内部类 ---定义在类的内部的类 为什么需要内部类? 典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象.所以你可以认为内部类提供了某种进入其外围类的窗口. java ...

  5. 自学java 第十章内部类(一)

    今天学习了一部分java中的内部类. 内部类指将一个类的定义放在另一个类的内部,那它就是一个内部类. 指明一个引用时内部类的类型可以通过"外部类名.内部类名"的写法声明,如果想返回 ...

  6. Java Nested Classes(内部类~第一篇英文技术文档翻译)

    鄙人最近尝试着翻译了自己的第一篇英文技术文档. Java Nested Classes Reference From Oracle Documentation 嵌套类-Nested Classes 在 ...

  7. java/c++中内部类、匿名类

    1.java中的内部类: class Outside{private String nameString ;private int age;Outside(){}Outside(String str_ ...

  8. java new 一个内部类_java内部类

    java内部类的几种类型:成员内部类,静态内部类,方法内部类,匿名内部类. 成员内部类:成员内部类是类内部的非静态类.成员内部类不能定义静态方法和变量(final修饰的除外).这是因为成员内部类是非静 ...

  9. 【JAVA】的内部类详解

    转载博客: https://www.cnblogs.com/dolphin0520/p/3811445.html 作者:海 子 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写 ...

  10. 深入理解Java中为什么内部类可以访问外部类的成员

    内部类简介 虽然Java是一门相对比较简单的编程语言,但是对于初学者, 还是有很多东西感觉云里雾里, 理解的不是很清晰.内部类就是一个经常让初学者感到迷惑的特性. 即使现在我自认为Java学的不错了, ...

最新文章

  1. java基础面试题整理-2021
  2. 在python中查看关键字、需要执行_python关键字以及含义,用法
  3. 工作207:修改表头按钮样式
  4. Citrix XenServer 池要求
  5. 签名(Signature)认证实现方式-用于请求鉴权
  6. 清除图片下默认的小间隙_PowerMILL软件应用策略(一):模型区域清除策略
  7. Windows窗体和常用控件的事件处理函数
  8. delete了,析构函数却没有调用
  9. SAP ABAP开发从入门到精通——第15章 面向对象ALV
  10. linux网卡驱动模块名称,Linux下根据模块名查看网卡驱动版本
  11. 荣耀手机不出鸿蒙系统,惊喜!4部荣耀手机可升级至华为鸿蒙系统,网友表示:终于等到了...
  12. Excel学习日记:L19-定义名称Indirect函数下拉选单设定
  13. Kyndryl从IBM完全剥离在纽交所独立上市;新思科技收购AI驱动性能优化软件企业Concertio | 全球TMT...
  14. FCOS:Fully Convolutional One-Stage Object Detection 论文翻译(非解读)
  15. 小生云服务器,HobitLab#2--云服务器的有效利用之搭建tiny tiny RSS
  16. Android 控件 RecyclerView简单使用
  17. 生命不息,折腾不止:Jetson Nano填坑之软件篇
  18. ASP.NET开发框架之ABP
  19. NK8.1-WY20-两种排序方法
  20. 安防PPP模式对智慧城市建设的影响和作用

热门文章

  1. C# 读取保存App.config配置文件的完整源码参考
  2. 使用socket的Linux上的C语言文件传输顺序服务器和客户
  3. Delphi下的GDI+编程[2] DrawLine - 绘制直线
  4. Win32环境下两种用于C++的线程同步类(上)
  5. BLE安全机制从入门到放弃
  6. STM32F103的11个定时器详解
  7. dingo php,用laravel dingo/api创建简单的api
  8. C++ Primer 5th笔记(chap 17 标准库特殊设施)IO库 之操纵符
  9. C++ Primer 5th笔记(chap 17 标准库特殊设施)ECMAScript正则表达式
  10. 如何优化Golang中重复的错误处理