Java基础——非静态内部类的实例必须依赖外部类的实例存在

2024-04-23 09:28

本文主要是介绍Java基础——非静态内部类的实例必须依赖外部类的实例存在,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

之前预习多态的时候,看到chatgpt3.5给的示例是经典的关于猫狗的举例。代码并不难,一看感觉就会,但是放到idea就开始报错。。。。搞了好久换了好几次方式,才突然反应过来,其实有些基础知识忘记了。。。。记录下。

过程

chatgpt3.5给的示例如下:

// Animal 类,作为基类
class Animal {// 发出声音的方法public void makeSound() {System.out.println("动物发出声音");}
}// Dog 类,继承自 Animal 类
class Dog extends Animal {// 重写 makeSound 方法public void makeSound() {System.out.println("汪汪汪!");}
}// Cat 类,继承自 Animal 类
class Cat extends Animal {// 重写 makeSound 方法public void makeSound() {System.out.println("喵喵喵!");}
}// 多态示例
public class Main {// 接受 Animal 对象并调用 makeSound 方法public static void animalSound(Animal animal) {animal.makeSound();}public static void main(String[] args) {// 创建 Dog 和 Cat 对象Dog dog = new Dog();Cat cat = new Cat();// 调用 animalSound 方法并传入不同的对象animalSound(dog); // 输出:"汪汪汪!"animalSound(cat); // 输出:"喵喵喵!"}
}

将上述代码放入idea中显示如下:

package com.zj.polymorphism;
/*** Java中多态使用示例* 多态定义:允许不同对象对同一消息做出不同的反应* 方法重现,方法重载,以及接口的实现体现了多态
* */
public class PolymorphismTest3 {// Animal 类,作为基类class Animal {// 发出声音的方法public void makeSound() {System.out.println("动物发出声音");}}// Dog 类,继承自 Animal 类class Dog extends Animal {// 重写 makeSound 方法public void makeSound() {System.out.println("汪汪汪!");}}// Cat 类,继承自 Animal 类class Cat extends Animal {// 重写 makeSound 方法public void makeSound() {System.out.println("喵喵喵!");}}// 多态示例// 接受 Animal 对象并调用 makeSound 方法public static void animalSound(Animal animal) {animal.makeSound();}public static void main(String[] args) {// 创建 Dog 和 Cat 对象Dog dog = new Dog();Cat cat = new Cat();// 调用 animalSound 方法并传入不同的对象animalSound(dog); // 输出:"汪汪汪!"animalSound(cat); // 输出:"喵喵喵!"}}

其实是会报错的,报错如下:
在这里插入图片描述

Inner classes cannot have static declarations:内部类不能有静态声明;

在这个地方idea提示其实有错误,更精确的说法是非静态内部类不能有静态声明。如果该内部类是静态的话,那么其内部是可以有静态声明的,是符合Java语法的。
那么就将这个Main内部类去掉就是了,单独放在外部类中,如下:
package com.zj.polymorphism;
/*** Java中多态使用示例* 多态定义:允许不同对象对同一消息做出不同的反应* 方法重现,方法重载,以及接口的实现体现了多态
* */
public class PolymorphismTest3 {// Animal 类,作为基类class Animal {// 发出声音的方法public void makeSound() {System.out.println("动物发出声音");}}// Dog 类,继承自 Animal 类class Dog extends Animal {// 重写 makeSound 方法public void makeSound() {System.out.println("汪汪汪!");}}// Cat 类,继承自 Animal 类class Cat extends Animal {// 重写 makeSound 方法public void makeSound() {System.out.println("喵喵喵!");}}// 多态示例// 接受 Animal 对象并调用 makeSound 方法public static void animalSound(Animal animal) {animal.makeSound();}public static void main(String[] args) {// 创建 Dog 和 Cat 对象Dog dog = new Dog();Cat cat = new Cat();// 调用 animalSound 方法并传入不同的对象animalSound(dog); // 输出:"汪汪汪!"animalSound(cat); // 输出:"喵喵喵!"}}

可是如此写之后还是会报错,报错如下:
在这里插入图片描述


cannot be referenced from a static context:不能够从静态上下文中引用。
就是从这里开始让我感到很疑惑的,因为一眼看上去,好像没有问题,就是在main方法中实例化Dog和Cat两个对象,然后将两个对象放到静态的animalSound方法中,传递的实例对象是子类Dog和Cat两个对象,而不是要求的Animal对象,这样的方式就已经体现了多态了(允许不同的对象对同一个消息做出不同的响应)。但是这个报错说明这样的写法有问题。
从报错上来说,不能够从静态上下文中引用,完全没头绪的。为什么不能引用,平常调用的时候不都是可以在静态Main主方法中实例化对象的吗????

总之懵逼了很久,才突然想到难道是因为静态的内部方法无法实例化同样的内部类吗?然后将main方法放到单独一个类中跟平常一样调用,结果还是失败的。。。。。这说明跟是否为静态的内部方法无关。。。
后来问chatgpt3.5联网版本才反应过来,这里的Dog和Cat是非静态内部类!!!
非静态内部类是必须要依赖外部类实例才能存在的!!!无论该非静态内部类是处于外部类的内部还是外部都是要先实例化外部类才能拿到该非静态内部类的实例
也就说,要实例化Dog和Cat对象,即使在外部类的内部,要实例化内部类也需要先实例化外部类才能得到非静态内部类的对象。
如下:
 public static void main(String[] args) {//方式一Animal dog = new PolymorphismTest2().new Dog();Animal cat = new PolymorphismTest2().new Cat();animalSound(dog);animalSound(cat);//方式二/*PolymorphismTest2 polymorphismTest = new PolymorphismTest2();polymorphismTest.animalSound(dog);polymorphismTest.animalSound(cat);*/}

按照上面方式写就不会报错。。。。

内省

真的,折腾这么久敢情就是一个非静态的内部类的实例化调用需要先调用外部类。。。。这个知识点并不是说我不知道,而是忽视了。。。因为如果平常是在外部的一个类调用另一个类的非静态内部类的时候这种使用场景就会自然而然的先实例化外部类再去实例化内部类,这个过程都没有感知的,因为有习惯了。但是在这里,因为是在同一个外部类的Main主方法内,想当然的以为不需要再实例化外部类就可以调用内部类了。。。。所以可以得知有些语法规则是要彻底的执行到底的,跟所处的范围是没有关系的,需要严格的执行。

这篇关于Java基础——非静态内部类的实例必须依赖外部类的实例存在的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/928410

相关文章

gradle第三方Jar包依赖统一管理方式

《gradle第三方Jar包依赖统一管理方式》:本文主要介绍gradle第三方Jar包依赖统一管理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景实现1.顶层模块build.gradle添加依赖管理插件2.顶层模块build.gradle添加所有管理依赖包

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环