java基础:熟悉3种内部类的写法,重点匿名内部类的使用

本文详细介绍了Java中的内部类概念,包括内部类的定义、分类及其应用场景。解释了成员内部类、方法内部类和匿名内部类的特点及使用场景,并提供了丰富的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、内部类定义

  内部类(nested classes),面向对象程序设计中,可以在一个类的内部定义另一个类。嵌套类分为两种,即静态嵌套类和非静态嵌套类。静态嵌套类使用很少,最重要的是非静态嵌套类,也即是被称作为内部类(inner)。内部类是JAVA语言的主要附加部分。内部类几乎可以处于一个类内部任何位置,可以与实例变量处于同一级,或处于方法之内,甚至是一个表达式的一部分。

  内部类是JAVA语言的主要附加部分。嵌套类从JDK1.1开始引入。其中inner类又可分为三种:
 
    其一、在一个类(外部类)中直接定义的内部类;
    其二、在一个方法(外部类的方法)中定义的内部类;
    其三、匿名内部类。

    

  为什么需要内部类?

    ⒈ 内部类对象可以访问创建它的对象的实现,包括私有数据;
    ⒉ 内部类不为同一包的其他类所见,具有很好的封装性;
    ⒊ 使用内部类可以很方便的编写事件驱动程序;
    ⒋ 匿名内部类可以方便的定义运行时回调
    5.内部类可以方便的定义

   每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

 


 

二、内部类分类

  一、成员内部类

    作为外部类的一个成员存在,与外部类的属性、方法并列。

    成员内部类也是定义在另一个类中,但是定义时不用static修饰。

  成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。

  成员内部类就像一个实例变量。

  它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以

  在外部类里面创建成员内部类的实例:

  this.new B();

  在外部类之外创建内部类的实例:

  (new Test1()).new B().go();

  在内部类里访问外部类的成员:

  Test1.this.member

  1. package memberiner;
  2. public class Test1 {
  3. private String member="这是外部类变量";
  4. //成员内部类
  5. //不对外开放,高内聚
  6. class B{
  7. public B() {//当内部类的构造器为Protected、private修饰时外部类外不可以访问
  8. }
  9. public void go(){
  10. System.out.println("这是内部类B的go方法"+Test1.this.member);//内部类访问外部类变量
  11. }
  12. }
  13. //可供成员的外部类中其他方法调用
  14. public B show(){
  15. return this.new B();//外部类调用
  16. }
  17. public static void main(String[] args) {
  18. B b = new Test1().show();
  19. }
  20. }
  21. package memberiner;
  22. public class A {
  23. public static void main(String[] args) {
  24. new Test1().show();
  25. (new Test1()).new B().go();//外部类外访问内部类
  26. }
  27. }

二、方法内部类(局部内部类)

   定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。

  像局部变量一样,不能被public, protected, private和static修饰。

  只能访问方法中定义的final类型的局部变量。

  方法内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成方法内部类的实例并且调用其方法

  

 
  1. package methodinner;
  2. public class Test {
  3. class Duanzanshichangzheng {
  4. public void noProblem() {
  5. System.out.println("患有急性短暂失常症,开车撞死人没事");
  6. }
  7. }
  8. private String member ="全局变量";
  9. final int n=4;
  10. public void driver(){
  11. final String member2 ="局部变量";//方法内的变量只有final变量才能被方法内部类访问
  12. System.out.println("我正在开车"+member);
  13. //每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,
  14. //对于内部类都没有影响
  15. //内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”
  16. //短暂,不对外,防止变成全局
  17. class B extends Duanzanshichangzheng {
  18. public void show(){
  19. System.out.println(member2+4);
  20. }
  21. }
  22. new B().noProblem();//方法内部类里的方法只能在方法里调用
  23. new B().show();
  24. System.out.println("一切恢复正常");
  25. }
  26. public static void main(String[] args) {
  27. new Test().driver();
  28. }
  29. }

三、匿名内部类(Android运用最多)

    匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。

    什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:


      a·只用到类的一个实例。
      b·类在定义后马上用到。
      c·类非常小(SUN推荐是在4行代码以下)
      d·给类命名并不会导致你的代码更容易被理解。


    在使用匿名内部类时,要记住以下几个原则:


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

  

以下是匿名内部类的实例:

  实例背景:输出每个Doctor博士每天做的事情

    1、白天大家都是“白天传授理论知识”;

    2、晚上每个人都是不一样的

  *用以前继承方法需要写多个实现类,而匿名内部类只需要实现“晚上做事workInNight()”这个方法就可以了

  代码目录

    

  1. package anonymousinner;
  2. public interface Qinshou {
  3. public void workInNight();
  4. }
 
  1. package anonymousinner;
  2. public abstract class Doctor implements Qinshou {
  3. //多态,情况不定
  4. public void workInDay(){
  5. System.out.println("白天传授理论知识");
  6. }
  7. }
  8. package anonymousinner;
  9. public class Doctor1 extends Doctor {
  10. public void workInNight(){
  11. System.out.println("晚上教弹琴");
  12. }
  13. }

  1. package anonymousinner;
  2. public class Doctor2 extends Doctor{
  3. public void workInNight(){
  4. System.out.println("晚上学习");
  5. }
  6. }
 
  1. package anonymousinner;
  2. public class Test {
  3. public static void main(String[] args) {
  4. Doctor1 d1 = new Doctor1();
  5. d1.workInDay();
  6. d1.workInNight();
  7. Doctor2 d2 = new Doctor2();
  8. d2.workInDay();
  9. d2.workInNight();
  10. //语法格式
  11. //1、new 抽象类或者接口
  12. //2、后加大括号
  13. //3、实现未实现方法
  14. Doctor d3 = new Doctor(){
  15. //匿名内部类
  16. public void workInNight() {
  17. System.out.println("睡觉");
  18. }
  19. };
  20. d3.workInDay();
  21. d3.workInNight();
  22. }
  23. }

 匿名内部类细节:

1、

  1. //1
  2. new Object(){
  3. void show(){
  4. System.out.println("show run");
  5. }
  6. }.show();//正确
  7. //2
  8. Object obj = new Object(){
  9. void show(){
  10. System.out.println("show run");
  11. }
  12. };
  13. obj.show();//编译错误
1和2的写法正确吗?有区别吗?说出原因。
    写法是正确,1和2都是在通过匿名内部类建立一个Object类的子类对象。
 区别:
 第一个可是编译通过,并运行。  第二个编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,就被提升为了 Object类型,而编译时检查Object类中是否有show方法,所以编译失败。 2、  
 
 
  1. class InnerClassDemo6 {
  2. +(static)class Inner{
  3. void show(){}
  4. }
  5. public void method(){
  6. this.new Inner().show();//可以
  7. }
  8. public static void main(String[] args) {//static不允许this
  9. This.new Inner().show();//错误,Inner类需要定义成static
  10. }
  11. }

还有很多的不懂,各位大神多多指教喔!




<think>好的,我现在需要回答用户关于JDK 1.8新特性及与其他版本区别的问题。首先,用户提到了参考引用中的内容,包括接口的默认方法、Optional类等,我需要确保这些信息准确无误地整合到回答中。 首先,我应该回顾JDK 1.8的主要新特性。根据引用[1]和[2],Lambda表达式和函数式编程是核心内容,还有接口的默认方法和静态方法,这改变了接口只能有抽象方法的传统。然后是新的日期时间API,这解决了旧版Date和Calendar的问题。Optional类用于处理空指针异常,Stream API用于集合操作,方法引用和重复注解也是重点。此外,还有并发增强和JVM方面的改进,比如元空间取代永久代。 接下来,我需要将这些特性分点说明,确保每个特性都有清晰的解释和示例。例如,在Lambda表达式部分,可以举一个排序的例子,对比传统方式和Lambda的简洁性。接口的默认方法需要说明其作用,比如允许接口添加新方法而不破坏现有实现,并给出示例代码。 关于与其他版本的区别,用户可能想知道1.8相较于之前版本(如1.7)和后续版本(如11或17)的不同。比如,与1.7相比,1.8引入了Lambda和Stream API,而1.7在资源管理和泛型推断上有改进。与后续版本相比,1.11的本地变量类型推断和1.17的密封类都是新内容。需要强调1.8的长期支持(LTS)地位,这是企业选择它的主要原因。 在版本选择建议部分,要分情况讨论。对于新项目,如果不需要最新功能,1.8是稳妥的选择;需要新特性则考虑11或17。维护旧项目时,升级到1.8可以平衡稳定性和功能。还要提到企业考虑因素,如框架兼容性和团队熟悉度。 需要确保回答结构清晰,使用用户提到的格式要求,比如行内公式用$...$,但这里可能不太涉及数学公式,不过要注意代码块的使用。引用部分要正确标注,比如接口默认方法引用[^1],Optional类引用[^2]。 最后,生成相关问题,确保覆盖用户可能进一步询问的方向,比如Lambda表达式的具体应用、1.8的缺点,或者升级版本的注意事项。 检查是否有遗漏的重要特性,比如并发增强中的CompletableFuture,或是JVM元空间的变化,这些也需要简要提及。同时,保持语言简洁,避免过于技术化,让不同层次的用户都能理解。 总结下来,回答的结构应该是:概述、新特性分点详述、与其他版本的比较、版本选择建议、相关问题。确保每个部分都有足够的细节和示例,同时引用正确的来源。</think>### JDK 1.8 新特性及与其他版本的区别 #### 一、JDK 1.8 核心新特性 1. **Lambda 表达式与函数式编程** 通过简化匿名内部类的语法,提升代码简洁性。例如集合排序: ```java // 传统写法 Collections.sort(list, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } }); // Lambda 写法 Collections.sort(list, (a, b) -> a.compareTo(b)); ``` 2. **接口的默认方法与静态方法** 允许接口包含具体实现的方法,解决接口扩展性问题。 ```java public interface Vehicle { default void print() { System.out.println("默认方法"); } static void honk() { System.out.println("静态方法"); } } ``` 3. **新的日期时间 API (`java.time`)** 引入不可变且线程安全的类如 `LocalDate`、`LocalTime`,替代易错的 `Date` 和 `Calendar`。 ```java LocalDate date = LocalDate.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String formattedDate = date.format(formatter); ``` 4. **Optional 类** 封装可能为 `null` 的对象,减少空指针异常。 ```java Optional<String> optional = Optional.ofNullable(getName()); optional.ifPresent(System.out::println); ``` 5. **Stream API** 支持链式操作和并行处理,简化集合操作。 ```java List<String> filtered = list.stream() .filter(s -> s.startsWith("A")) .collect(Collectors.toList()); ``` 6. **方法引用与重复注解** 方法引用进一步简化 Lambda 表达式(如 `System.out::println`),重复注解允许同一注解多次使用。 7. **并发增强** 新增 `CompletableFuture` 支持异步编程,`StampedLock` 优化读写锁性能。 8. **JVM 改进** 使用元空间(Metaspace)替代永久代(PermGen),降低内存溢出风险。 --- #### 二、与其他版本的区别 | 版本 | 关键特性对比 | |-----------|------------------------------------------------------------------------------| | **JDK 1.7** | 新增 `try-with-resources` 自动资源管理、泛型类型推断(`<>` 操作符)、NIO 2.0 | | **JDK 11** | 引入 `var` 关键字(局部变量类型推断)、HTTP Client API、单文件源码直接运行 | | **JDK 17** | 密封类(Sealed Classes)、模式匹配 `instanceof`、移除实验性 AOT 编译器 | **核心差异**: - **函数式编程**:1.8 的 Lambda 和 Stream 是革命性变化,而 1.7 以语法糖为主。 - **长期支持(LTS)**:1.8 和 11、17 均为 LTS 版本,企业更倾向选择 1.8 作为稳定基线。 --- #### 三、版本选择建议 1. **新项目** - 若需稳定且生态兼容性强:**JDK 1.8** - 若需新特性(如模块化、协程):**JDK 11/17** 2. **旧项目维护** - 逐步升级至 **1.8** 以利用 Lambda 和性能优化,但避免直接跳转到非 LTS 版本。 3. **企业考量** - 框架兼容性(如 Spring Boot 2.x 默认支持 1.8)和团队技术栈熟悉度是关键因素。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值