Java 内部类种类及使用解析
内部类Inner Class
将相关的类组织在一起,从而降低了命名空间的混乱。
一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分。
Java中的内部类共分为四种:
静态内部类static inner class (also called nested class)
成员内部类member inner class
局部内部类local inner class
匿名内部类anonymous inner class
静态内部类Static Inner Class
最简单的内部类形式。
类定义时加上static关键字。
不能和外部类有相同的名字。
被编译成一个完全独立的.class文件,名称为OuterClass$InnerClass.class的形式。
只可以访问外部类的静态成员和静态方法,包括了私有的静态成员和方法。
生成静态内部类对象的方式为:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
静态内部类使用代码:
1 package com.learnjava.innerclass; 2 3 class StaticInner 4 { 5 private static int a = 4; 6 7 // 静态内部类 8 public static class Inner 9 { 10 public void test() 11 { 12 // 静态内部类可以访问外部类的静态成员 13 // 并且它只能访问静态的 14 System.out.println(a); 15 } 16 17 } 18 } 19 20 public class StaticInnerClassTest 21 { 22 23 public static void main(String[] args) 24 { 25 StaticInner.Inner inner = new StaticInner.Inner(); 26 inner.test(); 27 } 28 }
成员内部类Member Inner Class
成员内部类也是定义在另一个类中,但是定义时不用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
成员内部类就像一个实例变量。
它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new Innerclass();
在外部类之外创建内部类的实例:
(new Outerclass()).new Innerclass();
在内部类里访问外部类的成员:
Outerclass.this.member
详情见代码例子:
1 package com.learnjava.innerclass; 2 3 class MemberInner 4 { 5 private int d = 1; 6 private int a = 2; 7 8 // 定义一个成员内部类 9 public class Inner2 10 { 11 private int a = 8; 12 13 public void doSomething() 14 { 15 // 直接访问外部类对象 16 System.out.println(d); 17 System.out.println(a);// 直接访问a,则访问的是内部类里的a 18 19 // 如何访问到外部类里的a呢? 20 System.out.println(MemberInner.this.a); 21 } 22 23 } 24 25 } 26 27 public class MemberInnerClassTest 28 { 29 30 public static void main(String[] args) 31 { 32 33 // 创建成员内部类的对象 34 // 需要先创建外部类的实例 35 MemberInner.Inner2 inner = new MemberInner().new Inner2(); 36 37 inner.doSomething(); 38 } 39 }
局部内部类Local Inner Class
局部内部类定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public, protected, private和static修饰。
只能访问方法中定义的final类型的局部变量。
局部内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成局部内部类的实例并且调用其方法。
1 package com.learnjava.innerclass; 2 3 class LocalInner 4 { 5 int a = 1; 6 7 public void doSomething() 8 { 9 int b = 2; 10 final int c = 3; 11 // 定义一个局部内部类 12 class Inner3 13 { 14 public void test() 15 { 16 System.out.println("Hello World"); 17 System.out.println(a); 18 19 // 不可以访问非final的局部变量 20 // error: Cannot refer to a non-final variable b inside an inner 21 // class defined in a different method 22 // System.out.println(b); 23 24 // 可以访问final变量 25 System.out.println(c); 26 } 27 } 28 29 // 创建局部内部类的实例并调用方法 30 new Inner3().test(); 31 } 32 } 33 34 public class LocalInnerClassTest 35 { 36 public static void main(String[] args) 37 { 38 // 创建外部类对象 39 LocalInner inner = new LocalInner(); 40 // 调用外部类的方法 41 inner.doSomething(); 42 } 43 44 }
匿名内部类Anonymous Inner Class
匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。
匿名内部类隐式地继承了一个父类或者实现了一个接口。
匿名内部类使用得比较多,通常是作为一个方法参数。
1 package com.learnjava.innerclass; 2 3 import java.util.Date; 4 5 public class AnonymouseInnerClass 6 { 7 8 @SuppressWarnings("deprecation") 9 public String getDate(Date date) 10 { 11 return date.toLocaleString(); 12 13 } 14 15 public static void main(String[] args) 16 { 17 AnonymouseInnerClass test = new AnonymouseInnerClass(); 18 19 // 打印日期: 20 String str = test.getDate(new Date()); 21 System.out.println(str); 22 System.out.println("----------------"); 23 24 // 使用匿名内部类 25 String str2 = test.getDate(new Date() 26 { 27 });// 使用了花括号,但是不填入内容,执行结果和上面的完全一致 28 // 生成了一个继承了Date类的子类的对象 29 System.out.println(str2); 30 System.out.println("----------------"); 31 32 // 使用匿名内部类,并且重写父类中的方法 33 String str3 = test.getDate(new Date() 34 { 35 36 // 重写父类中的方法 37 @Override 38 @Deprecated 39 public String toLocaleString() 40 { 41 return "Hello: " + super.toLocaleString(); 42 } 43 44 }); 45 46 System.out.println(str3); 47 } 48 }
生成的.class文件中,匿名类会生成OuterClass$1.class文件,数字根据是第几个匿名类而类推。
Swing中使用内部类的例子如下:
1 package com.learnjava.innerclass; 2 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.awt.event.WindowAdapter; 6 import java.awt.event.WindowEvent; 7 8 import javax.swing.JButton; 9 import javax.swing.JFrame; 10 11 public class SwingTest 12 { 13 public static void main(String[] args) 14 { 15 JFrame frame = new JFrame("JFrame"); 16 JButton button = new JButton("JButton"); 17 18 button.addActionListener(new ActionListener() 19 { 20 // new出来一个实现了ActionListener接口的类的实例 21 22 @Override 23 public void actionPerformed(ActionEvent arg0) 24 { 25 System.out.println("Hello World"); 26 27 } 28 }); 29 30 //加入按钮 31 frame.getContentPane().add(button); 32 33 //设置关闭行为 34 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 35 36 frame.setSize(200, 200); 37 38 frame.addWindowListener(new WindowAdapter() 39 { 40 //也可以使用继承了适配器类的匿名内部类 41 @Override 42 public void windowClosing(WindowEvent e) 43 { 44 45 System.out.println("Closing"); 46 System.exit(0); 47 } 48 }); 49 frame.setVisible(true); 50 } 51 52 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示