Java文件中为什么只能有一个public修饰的类, 并且类名还必须与文件名相同
当编写一个java源代码文件时,此文件通常被称为编译单元(有时也被称为转译单元)。每个编译单元都必须有一个后缀名.java,而在编译单元内则可以有一个public类,该类的名称必须与文件的名称相同(包括大小写,但不包括文件的后缀名.java)。每个编译单元只能有一个public类,否则编译器就不会接受(即只能有0-1个public类)。如果在该编译单元之中还有额外的类的话(即其他非public类),那么在包之外的世界是无法看见这些类的,这是因为它们不是public类,而且它们主要用来为主public类提供支持。
首先说一下为什么public的类名要与.java文件名一致的问题~
B.java文件
package com.culiu.ccj.servant.tagstatistics.test; /**
* 描述:
* 创建人: BruceCloud
* 创建时间: 2016/5/18 10:10.
*/
public class B {
} class C{
}
Test.java文件
package com.culiu.ccj.servant.tagstatistics.test.aa; import com.culiu.ccj.servant.tagstatistics.test.B; /**
* 描述:
* 创建人: BruceCloud
* 创建时间: 2016/5/18 10:10.
*/
public class Test {
public static void main(String[] args) {
try {
B a = new B();
// C c = new C();
Class c = Class.forName("com.culiu.ccj.servant.tagstatistics.test.C");
System.out.println(c.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
上面代码B.java中, 有2个类(public B和非public的 C), 在B.java这个编译单元中, public B是该编译单元对外的接口类, C则是包内使用的类, 根据java的编程规则, 在Test.java中第14行引入C时会编译出错, 提示你找不到C这个类, 因为C没有被public修饰,
所以C只能在com.culiu.ccj.servant.tagstatistics.test包下面使用, 而第13行B却可以使用, 因为在使用B的时候在上面使用了import com.culiu.ccj.servant.tagstatistics.test.B;对B进行了导入(可以导入的前提是com.culiu.ccj.servant.tagstatistics.test.B
这个编译单元提供了对外公开的接口, 即public修饰的类), 而你使用import com.culiu.ccj.servant.tagstatistics.test.C;的时候会报错, 提示你找不到C, 因为不存在com.culiu.ccj.servant.tagstatistics.test.C这个编译单元(即使存在也不存在public入口)~~
接下来在程序运行到Test.java第13行时, jvm会去加载B这个类, 而加载的方式就是通过import后面的编译单元名称进行加载的(即通过com.culiu.ccj.servant.tagstatistics.test.B进行加载的, 加载的内容就是该编译单元的入口类, 就是public修饰的类), 所以
public修饰的的类名必须要与.java文件名一致, 就是为了方便在加载编译单元入口类的时候不用在进行名字转换了, 这样省了很多麻烦, 直接去加载com.culiu.ccj.servant.tagstatistics.test.B.class就行了, 而无需在进行名字转换~~~
试想一下, 如果B.java中的public类的名字是C, 那么在加载编译单元B的时候还需要去查找编译单元B的入口类名字, 假想步骤如下:
1.取得编译单元B的位置import com.culiu.ccj.servant.tagstatistics.test.B;
2.再在1的位置中找到要加载的入口类(此时因为public的类名跟B.java的文件名不一致, 所以无法直接通过1中的com.culiu.ccj.servant.tagstatistics.test.B.class来加载了, 需要进行
入口类的名称查找或者转换, 最终加载的也就是com.culiu.ccj.servant.tagstatistics.test.C.class)
这样会很麻烦~~莫不如直接规定public的类与.java文件名相同~~~
PS: 上面Test.java中有一点需要注意, 虽然B.java中的C类无法在其他包下使用, 但是却可以在其他包下通过反射来进行加载~~如第15行~~
到此, 为什么public类名必须和.java文件名相同的问题讲完了~~
接下来讲为什么.java文件中只能有一个public类~~~
因为在文件系统中, 一个文件只能有一个名字, 这里的情况就是一个编译单元(即.java文件)只能有一个名, 而这个名字的作用恰好还是jvm用来加载该编译单元入口类的, 而上面讲了jvm在
加载编译单元入口类的时候是通过编译单元名字来进行加载的, , 所以如果你的编译单元中有多个public类(即有多个入口), 那么jvm就无法分辨到底要去加载哪个入口类了~~
到此, 为什么.java文件中只能有一个public类的问题讲完了~~
写在最后:
以上内容都是本人自己的理解, 不敢保证java设计者们就是这么想的, 我写出的目的也方便日后自己忘了的时候还能翻出来此文再来回想一下曾经的想法~~
欢迎各路Java大神来讨论一下并留下自己的理解~~一切的一切都是以最终能搞明白问题的本质为目的~~所以还请口下留情~~
Java文件中为什么只能有一个public修饰的类, 并且类名还必须与文件名相同的更多相关文章
- 一个java源文件中为什么只能有一个public类。
我们都遇到过一个源文件中有多个java类,但当第一个类使用public修饰时,如果下面还有类使用public修饰,会报错.也就是是说一个java源文件最多只能有一个public类. 当有一个publi ...
- java-源文件中可以有多个类,但是最多只能有一个public修饰
1.如果源文件中有多个类,那么只能有一个类是public类:如果有一个类是public类,那么源文件的名字必须与这个类的名字完全相同,扩展名是.java. 2.如果源文件中没有public类,那么源文 ...
- 第7章 一个java源文件中只能有一个public类
一个Java源文件中最多只能有一个public类, 1)当有一个public类时,源文件名必须与之一致,否则无法编译, 2)如果源文件中没有一个public类,则文件名与类中没有一致性要求. 至于ma ...
- 浅谈为什么一个java源文件中只能有一个public类?
声明,本篇文章为转载 转载 http://blog.csdn.net/bareheadzzq/article/details/6562211 最近在一个java文件中实现了几个类,其中一个声明为pub ...
- 为什么一个java源文件中只能有一个public类
问题:一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 答案:可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致.一个文件 ...
- 一个.java文件中可以有几个同级类
1.在一个.java文件中可以有几个类.修饰符只可以public abstract final和无修饰符,不能是其他的private等修饰符.2.public修饰的只能有一个,且要与文件名相同 若没有 ...
- 一个.java文件中是否可以有多个类
前段时间,有个同事问到我这个问题:一个.java文件中是否可以有多个类? 答案:可以有多个类,但最多只能有一个被public修饰的class. 且若这个.java文件中有一个public类型的clas ...
- 一个项目中:只能存在一个 WebMvcConfigurationSupport (静态文件失效之坑)
一个项目中:只能存在一个 WebMvcConfigurationSupport 在一个项目中WebMvcConfigurationSupport只能存在一个,多个的时候,只有一个会生效. 静态文件访问 ...
- JAVA文件中获取路径及WEB应用程序获取路径方法
JAVA文件中获取路径及WEB应用程序获取路径方法 1. 基本概念的理解 `绝对路径`:你应用上的文件或目录在硬盘上真正的路径,如:URL.物理路径 例如: c:/xyz/test.txt代表了tes ...
随机推荐
- openstack controller ha测试环境搭建记录(一)——操作系统准备
为了初步了解openstack controller ha的工作原理,搭建测试环境进行学习. 在学习该方面知识时,当前采用的操作系统版本是centos 7.1 x64.首先在ESXi中建立2台用于测试 ...
- Docker - 容器编排工具 compose 之安装
准备 首先,在使用和安装 docker compose之前,我们应该确保我们已经安装了 docker engine. 安装 官网上面有好多种安装方式,由于我们现在是在使用Docker, 个人感觉应该以 ...
- ComboBox值排序
ComboBox值排序先是想通过冒泡排序,但是冒泡排序是int类型,又打算通过下标,进行字符串排序,然后想到了一个简单的办法……先存入ArrayList排序Sort清空ComboBox再遍历存入 ...
- display属性及inline-block值(可用来布局)
display:block就是将元素显示为块级元素. block元素的特点是: 总是在新行上开始: 高度,行高以及顶和底边距都可控制: 宽度缺省是它的容器的100%,除非设定一个宽度 <div& ...
- UISwitch——开关控件
开关的可配置选项很少,一般用于处理布尔值. 下面给出一个小Demo,创建两个开关,开关一可以控制开关二的可用与否,两者的关系就相当于水闸与水龙头的关系. #import "ViewContr ...
- BZOJ 1653 [Usaco2006 Feb]Backward Digit Sums ——搜索
[题目分析] 劳逸结合好了. 杨辉三角+暴搜. [代码] #include <cstdio> #include <cstring> #include <cmath> ...
- java线程 — 创建和启动线程
创建和启动线程,传统有两种方式: 方式1:继承Thread类: 方式2:实现Runnable接口: 线程类(java.lang.Thread):Thread类和Thread的子类才能称之为线程类.阅读 ...
- mongodb 查询时没有索引报错(too much data for sort() with no index)
报错信息: .... too much data for sort() with no index.... 给对应排序字段加索引就OK 了... 在对应"表"名上,右键--> ...
- RabbitMQ消息队列(三):任务分发机制
在上篇文章中,我们解决了从发送端(Producer)向接收端(Consumer)发送“Hello World”的问题.在实际的应用场景中,这是远远不够的.从本篇文章开始,我们将结合更加实际的应用场景来 ...
- 命名空间“Microsoft.AspNet”中不存在类型或命名空间名“Mvc”
问题: 错误 CS0234 命名空间"Microsoft.AspNet"中不存在类型或命名空间名"Mvc"(是否缺少程序集引用?) 解决方案: 打开文件夹 Us ...