【Java基础】一个Java文件可以有多个类(外部类、内部类)

news2024/11/18 15:50:30

目录

  • 一、在一个Java文件中定义多个类(外部类)
    • 1.问题描述及解答
    • 2.总结
  • 二、在一个Java文件定义多个类(内部类)
    • 1.成员内部类和匿名内部类
      • 1.1 成员内部类
      • 1.2 匿名内部类
    • 2.深入理解内部类
    • 3.内部类的使用场景和好处

一、在一个Java文件中定义多个类(外部类)

1.问题描述及解答

1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

答案:可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。一个文件中可以只有非public类,如果只有一个非public类,此类可以跟文件名不同。

2、为什么一个java源文件中只能有一个public类?

在java编程思想(第四版)一书中有这样3段话(6.4 类的访问权限):

  1. 每个编译单元(文件)都只能有一个public类,这表示,每个编译单元都有单一的公共接口,用public类来表现。该接口可以按要求包含众多的支持包访问权限的类。如果在某个编译单元内有一个以上的public类,编译器就会给出错误信息。
  2. public类的名称必须完全与含有该编译单元的文件名相同,包含大小写。如果不匹配,同样将得到编译错误。
  3. 虽然不是很常用,但编译单元内完全不带public类也是可能的。在这种情况下,可以随意对文件命名。

3、当java源文件不存在public类时,会出现什么情况?

在这里插入图片描述  此时程序编译通过,在相应路径下产生了三个.class文件。直接点击运行,程序是不能运行的,我们需要鼠标右键点击程序----->Run As----->Java Aplication----->选数据来源
在这里插入图片描述

2.总结

一个编译单元(java文件)可以存在多个类,在编译时产生多个不同的.class文件,.class文件便是程序运行的数据来源。java将public类作为每个编译单元的数据接口,只能有一个,不然不能处理存在多个类的java文件。当一个编译单元(java文件)有多个非public类时,运行时需要对数据来源进行选择。

在这里插入图片描述
在这里插入图片描述

二、在一个Java文件定义多个类(内部类)

在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。其中成员内部类匿名内部类比较常见。

下面我将对成员内部类和匿名内部类进行专讲,其他内部类可参考链接:菜鸟教程-Java内部类详解。

1.成员内部类和匿名内部类

1.1 成员内部类

先说结论:

  • 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
  • 虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。
    成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
class Circle {
    double radius = 0;
     
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println("drawshape");
        }
    }
}

这样看起来,类Draw像是类Circle的一个成员,Circle称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

class Circle {
    private double radius = 0;
    public static int count =1;
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
            System.out.println(count);   //外部类的静态成员
        }
    }
}

不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:

外部类.this.成员变量
外部类.this.成员方法

虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:

class Circle {
    private double radius = 0;
 
    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问
    }
     
    private Draw getDrawInstance() {
        return new Draw();
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
        }
    }
}

成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:

public class Test {
    public static void main(String[] args)  {
        //第一种方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建
         
        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
 
class Outter {
    private Inner inner = null;
    public Outter() {
         
    }
     
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
      
    class Inner {
        public Inner() {
             
        }
    }
}

内部类可以拥有 private 访问权限、protected 访问权限、public 访问权限及包访问权限。比如上面的例子,如果成员内部类 Inner 用 private 修饰,则只能在外部类的内部访问,如果用 public 修饰,则任何地方都能访问;如果用 protected 修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被 public 和包访问两种权限修饰。我个人是这么理解的,由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。

1.2 匿名内部类

匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。下面这段代码是一段 Android 事件监听代码:

scan_bt.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
         
    }
});
 
history_bt.setOnClickListener(new OnClickListener() {
     
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
         
    }
});

这段代码为两个按钮设置监听器,这里面就使用了匿名内部类。这段代码中的:

new OnClickListener() {
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
         
    }
}

就是匿名内部类的使用。代码中需要给按钮设置监听器对象,使用匿名内部类能够在实现父类或者接口中的方法情况下同时产生一个相应的对象,但是前提是这个父类或者接口必须先存在才能这样使用。当然像下面这种写法也是可以的,跟上面使用匿名内部类达到效果相同。

private void setListener()
{
    scan_bt.setOnClickListener(new Listener1());       
    history_bt.setOnClickListener(new Listener2());
}
 
class Listener1 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
             
    }
}
 
class Listener2 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
             
    }
}

这种写法虽然能达到一样的效果,但是既冗长又难以维护,所以一般使用匿名内部类的方法来编写事件监听代码。同样的,匿名内部类也是不能有访问修饰符和 static 修饰符的。

匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为 Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

2.深入理解内部类

1、为什么成员内部类可以无条件访问外部类的成员?

在这里插入图片描述

3.内部类的使用场景和好处

为什么在 Java 中需要内部类?总结一下主要有以下四点:

  1. 每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整。
  2. 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
  3. 方便编写事件驱动程序。
  4. 方便编写线程代码。

个人觉得第一点是最重要的原因之一,内部类的存在使得Java的多继承机制变得更加完善。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409479.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小米商城官网(登录页,首页,详情页,我的购物车页,我的订单页,确认订单页)HTML+CSS+JS

文章目录前言一、登录页二、首页三、我的购物车页四、我的订单页五、确认订单页六、详情页七、整体结构和效果图总结前言 仿小米商城官网项目是本人实训内容,实训老师带着做的首页和登录页,本人在此基础上加入了我的购物车页,我的订单页&…

vue兼容ie11(@babel/polyfill、core-js@3两种方式)

Babel介绍: Babel是一个JavaScript编译器,主要用于将ECMAScript 2015代码转换为当前和旧浏览器或环境中向后兼容的JavaScript版本。要是通过核心依赖core-js2,主要是通过核心依赖core-js2来完成对应浏览器不支持的新的全局和实例api的添加 …

Vue2 实现图片的拖拽、缩放、旋转

本文是基于vue2 实现图片的拖拽、旋转、鼠标滚动放大缩小等功能。 效果图 分步骤实现 在这里看下 拖拽、旋转、缩放的几个方法 1.获取图片的实际宽高 getImgSize(url) {return new Promise((resolve, reject) > {let imgObj new Image();imgObj.src url;imgObj.onload…

插槽(slot)的基本使用

插槽(slot)的基本使用 一、插槽的作用 在开发中,我们会经常封装一个个可复用的组件: 前面我们会通过props传递给组件一些数据,让组件来进行展示; 但是为了让这个组件具备更强的通用性,我们不能…

Ubuntu搭建web站点并发布公网访问【内网穿透】

文章目录前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名前言 网:我们通常说的是互联网;站…

Vue3中使用vant(踩坑日记....)

我照着视频中老师教的方式去使用vant(和官网教程一样),发现样式根本不起作用(想截个图来着,但是vite热更新太厉害了,找不到了哈哈哈),然后又反复看了视频一遍,检查自己插件啥的而又没有安装好&a…

【TypeScript基础】TypeScript之常用类型(上)

前言 博主主页👉🏻蜡笔雏田学代码 专栏链接👉🏻【TypeScript专栏】 上篇文章大概了解了一下TypeScript,👉🏻详细内容请阅读【TypeScript介绍】一文带你初步了解TypeScript 今天开始学习学习Type…

html实现用户注册页面(生日实现年月日的三级联动)

注册页面 期待效果如下&#xff1a; 初始代码实现&#xff1a; <!DOCTYPE html> <html> <head><title>注册页面</title> </head> <body> <!-- 表单&#xff0c;用于提交按钮&#xff0c;隐式提交 --> <form action"…

后台管理系统 - 页面布局设计

前端的中后台管理系统相比于其他普通项目&#xff0c;从开发设计的角度来说有几点比较特殊&#xff1a; 一个是权限设计&#xff0c;具体实现可参考&#xff1a;传送门。一个是页面布局的设计&#xff0c;也是本文要说的。一个好的页面布局设计&#xff0c;无论是对于页面结构…

Java Web实现登录注册(超详细附代码)

Java Web实现登录注册&#xff08;超详细附代码&#xff09; 文章目录Java Web实现登录注册&#xff08;超详细附代码&#xff09;1.前言2.登录注册设计流程3.注册的数据流程4.登录的数据流程5.部分代码的展示5.1注册5.2登录6.总结1.前言 相信刚学Javaweb的小伙伴第一个接触的…

30个极致实用的谷歌浏览器插件,让你开发事半功倍

浏览器是开发人员最强大的工具。99% 的人不会 100% 地利用他们的浏览器。这里有 30 个浏览器扩展&#xff0c;如果你能合理充分利用将大大提升你的开发效率。1. WhatFont"WhatFont"&#xff0c;是一款帮助用户快速识别网页中字体信息的工具。当你在浏览网页时&#x…

vue|axios发送post请求详解

axios发送Post请求 首先我们要知道发送一个请求体的时候我们要明确发送的类型是什么&#xff0c;常见的类型有三种 form-dataapplication/jsonapplication/x-www-form-urlencoded 以上三种类型是进行数据传输的数据类型&#xff0c;我们知道在js代码中的对象都不是以上的三种…

react实现路由跳转

react通过路由实现页面跳转&#xff1a; ​ 函数式路由(withRouter)使用原生js方法实现路由功能。 ​ eg&#xff1a;export default withRouter(Home) Home是组件名称。 示例&#xff1a;class Home extends Component{<button onClick{this.goForward}>下一级</bu…

猿创征文|【C++游戏引擎Easy2D】炫酷动画来这学,位移动画构造函数让节点执行动画

&#x1f9db;‍♂️iecne个人主页&#xff1a;&#xff1a;iecne的学习日志 &#x1f4a1;每天关注iecne的作品&#xff0c;一起进步 &#x1f4aa;学C必看iecne 本文专栏&#xff1a;【C游戏引擎】. &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; ✨前…

from origin ‘null‘ has been blocked by CORS policy: Cross origin requests are only supported for ...

跨源资源请求问题解决方案 问题描述&#xff1a;当我们在vsCode中使用 open in brower插件打开html文件文件时&#xff0c;就会报错 xxx已被CORS策略阻止&#xff0c;引入的资源还会失效。 解决办法1 :Live Server插件 在vsCode的插件市场中搜索并安装Live Server插件&#x…

Axios

Axios是Ajax的一个框架&#xff0c;简化Ajax操作 一、基本操作 Axios执行Ajax的操作&#xff1a; 1. 添加axios的js文件 <script language"JavaScript" src"script/axios.min.js"></script> 2.1 客户端向服务端异步发送普通参数值 格式&am…

vue-router报错: uncaught error during route navigation

bug场景&#xff1a; H5项目中,浏览器流程走的通,ios流程走得通,安卓机有的可以有的不行 报错信息&#xff1a; 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 例如&#xff1a;数据传输过程中数据不时出现丢失的情况&#xff0c;偶尔会丢失一部分数据 APP 中接收数…

尚融宝06-ECMAScript基本介绍和使用

目录 一、ECMAScript 1、ECMA 2、ECMAScript 3、什么是 ECMA-262 4、ECMA-262 历史 5、ECMAScript 和 JavaScript 的关系 二、基本语法 1、let声明变量 2、const声明常量 3、解构赋值 4、模板字符串 5、声明对象简写 6、定义方法简写 7、参数的默认值 8、对象拓…

less变量

Less变量一、Less简介二、Less中的变量三、less外部引入一、Less简介 1.Less是一门css的预处理语言&#xff0c;less是一个css的增强版&#xff0c;通过less可以编写更少的代码实现更强大的样式。 变量名以两条短横线命名 例如&#xff1a; --color&#xff1a;red 2.Less特…

vue的created函数中方法执行的顺序设置方法

1.vue的created钩子函数中&#xff0c;方法的执行顺序 1.1情景&#xff1a;vue框架中通常在created钩子函数里执行访问数据库的方法&#xff0c;然后返回数据给前端&#xff0c;前端data中定义全局变量接收数据 1.2误区&#xff1a;我们可能会思考按照自己设定好的逻辑走&…