摘要:外部类也可以直接访问内部类的所有属性和方法。匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。创建内部类对象的时刻并不依赖于外围类对象的创建。内部类并没有令人迷惑的关系,他就是一个独立的实体。
基本概念
可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
广泛意义上的内部类一般来说包括这四种:
成员内部类
局部内部类
静态内部类
匿名内部类
成员内部类成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
public class testDemo { public static void main(String[] args ) { Outer t = new Outer(); Outer.Inner in = t.new Inner(); // 必须先有外部类对象,才能创建内部类 t.fun(); in.print(); } } class Outer { //外部类 private String msg = "hello world"; public void fun(){ Inner in = new Inner(); System.out.println(in.info); //外部类直接访问内部类的私有属性 } class Inner{ //定义了一个成员内部类 private String info = "世界,你好!"; public void print(){ System.out.println(msg); //内部类直接访问外部类的private属性 } } }
成员内部类可以无条件访问外部类的所有属性和方法(包括private成员和静态成员)。外部类也可以直接访问内部类的所有属性和方法。
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象
在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量 外部类.this.成员方法局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的作用域仅限于方法内或者该作用域内。
public class testDemo { public static void main(String[] args ) { new Outer().fun(); } } class Outer { //外部类 private String msg = "hello world"; public void fun(){ class Inner{ //在方法中定义了一个局部内部类 public void print(){ System.out.println(Outer.this.msg); //直接访问外部类的private属性 } } new Inner().print(); } }
注意:局部内部类就像是方法里面的一个局部变量一样。
在jdk1.7或之前的版本,如果局部内部类要访问方法中定义的参数、局部变量,那么参数和变量前一定要加上"final"修饰符。jdk1.8以及更新的版本则没有这个限制。
public class testDemo { public static void main(String[] args ) { new Outer().fun(100); } } class Outer { //外部类 private String msg = "hello world"; public void fun(final int num){ final double score = 99.9; class Inner{ //在方法中定义了一个局部内部类 public void print(){ System.out.println("属性:"+Outer.this.msg); //直接访问外部类的private属性 System.out.println("方法参数"+ num); System.out.println("方法局部变量"+ score); } } new Inner().print(); } }静态内部类
使用static修饰的成员内部类叫静态内部类。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能访问外部类的非static成员变量或者方法。
public class testDemo { public static void main(String[] args ) { Outer.Inner in = new Outer.Inner(); //静态内部类可以使用"外部类.内部类"的方式使用 in.print(); } } class Outer { //外部类 static class Inner{ //定义了一个静态内部类 private String info = "世界,你好!"; public void print(){ System.out.println(info); } } }匿名内部类
当某个子类只使用唯一一次的时候,没有必要多带带定义出来,可以使用匿名内部类的方法简化代码。
匿名内部类就是没有名字的局部内部类。创建格式如下:
new 父类构造器(参数列表)| 要实现的接口 () { //匿名内部类的类体部分 //.... }
匿名内部类是在抽象类和接口的基础上发展而来的,其最大的好处是帮助减少了类的定义。
在使用匿名内部类的过程中,我们需要注意如下几点:
使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
匿名内部类中是不能定义构造函数的。
匿名内部类中不能存在任何的静态成员变量和静态方法。
匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
当所在的方法的形参需要被内部类里面使用时,该形参必须为final(jdk1.8之后可省略)。
示例:
//接口 interface Inner { public String say(); } //抽象类 abstract class Inner1 implements Inner{ } //普通类 class Inner2 implements Inner{ public String say(){ return "this is Inner2"; } } class Outer { public void method1(Inner inner) { System.out.println(inner.say()); } } public class testDemo { public static void main(String[] args) { Outer outer = new Outer(); // 测试1,Inner为接口 outer.method1(new Inner() { String s1 = "this is s1 in Inner"; public String say() { // 外部类和匿名函数类中有同名变量s1 return s1; } }); // 测试2,Inner1为抽象类 outer.method1(new Inner1() { String s2 = "this is s2 in Inner1"; public String say() { // 外部类和匿名函数类中有同名变量s2 return s2; } }); //测试3, Inner2为普通类 outer.method1(new Inner2() { public String say() { return "this is inner2 overrite"; } }); } } 输出结果: this is s1 in Inner this is s2 in Inner1 this is inner2 overrite内部类的作用
为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。内部类最大的优点就在于它能够非常好的解决多重继承的问题.
内部类还能够为我们带来如下特性:
内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
创建内部类对象的时刻并不依赖于外围类对象的创建。
内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/73532.html
摘要:目录介绍问题汇总具体问题好消息博客笔记大汇总年月到至今,包括基础及深入知识点,技术博客,学习笔记等等,还包括平时开发中遇到的汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善开源的文件是格式的同时也开源了生活博客,从年 目录介绍 00.Java问题汇总 01.具体问题 好消息 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技...
摘要:鄙人最近尝试着翻译了自己的第一篇英文技术文档。如果我们需要在其他外部类中使用内部类,则一定要将嵌套类声明为或者。方法中的会覆盖掉内部类中的。因此,对于一个内部类序列化后,使用不同的进行反序列化的话,可能会存在兼容性的问题。 鄙人最近尝试着翻译了自己的第一篇英文技术文档。Java Nested Classes Reference From Oracle Documentation 嵌套类...
摘要:拆箱将包装类型转换为基本类型的过程。否则会抛出异常。默认采用单链表解决冲突,如果链表长度超过,将单链表转换为红黑树。内部使用红黑树实现,存储映射。红黑树减弱了对平衡的要求,降低了保持树平衡需要的开销,在实际应用中,统计性能超过平衡二叉树。 引言 showImg(https://segmentfault.com/img/bVbv7Mr?w=242&h=410); 在学习《Java编程的逻...
摘要:可实现单例模式代码块初始化静态变量,只被执行一次内部类不能与外部类重名,只能访问外部类静态数据包括私有多分支选择整型或字符类型变量或整数表达式开始支持。 前言 大学期间接触 Java 的时间也不短了,不论学习还是实习,都让我发觉基础的重要性。互联网发展太快了,各种框架各种技术更新迭代的速度非常快,可能你刚好掌握了一门技术的应用,它却已经走在淘汰的边缘了。 而学习新技术总要付出一定的时间...
摘要:请注意,应用程序类加载器的模型与此略有不同,如下所述,但主要原则是相同的。此类由加载器搜索的位置中的属性定义。该服务器类加载器是唯一到内部可见,并且是应用程序完全不可见。 Tomcat 7 类加载器是如何实现的 概述 与许多服务器应用程序一样,Tomcat安装了各种类加载器(即实现的类java.lang.ClassLoader),以允许容器的不同部分和容器上运行的Web应用程序访问可用...
阅读 3827·2023-04-26 00:36
阅读 2646·2021-11-16 11:44
阅读 1062·2021-11-15 17:58
阅读 1642·2021-09-30 09:47
阅读 1194·2019-08-30 13:05
阅读 1491·2019-08-30 12:55
阅读 2393·2019-08-30 11:02
阅读 2650·2019-08-29 17:01