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 ...
随机推荐
- iOS之NSPredicate(正则表达式和UIBarController)
本文转发至:https://segmentfault.com/a/1190000000623005 NSPredicate,这个类和我上一篇博文中提到的valueForKeyPath一样很强大.它的使 ...
- typedef和block
为block类型对象取别名 1.没有使用typedef的情况 int (^block_add)(int, int) = ^(int value1, int value2) { return value ...
- losbyday Linux查找命令
PS:第一次发表博客,试一下水,晚一点修改文本格式 linux下的命令都存放在/bin /sbin /usr/bin /usr/sbin路径下等echo $PATH which 是用来查询命令存放的路 ...
- Spring自学教程-介绍、特点、框架(一)
一.spring是什么,有什么用? 一句话:面向企业应用,使用javabean代替ejb的java应用或web开发. 侵入式的做法就是要求用户代码"知道"框架的代码,表现为用户代码 ...
- Eclipse中GIT插件更新工程到之前版本
因为之前好多次因为对项目文件删除后,发现删除的文件里有些功能模块还是需要的,所以需要恢复到之前的版本.但是一直不知道怎么操作才能恢复到之前版本,索性就直接把工程删了,重新导入,但是这太暴力了,所以看了 ...
- LPC1768的IIS通讯
IIS是飞利浦公司定义的一种用于音频传输的数字总线,LPC1768支持该总线, I2S接口为一条3线串行总线,含有1根数据线.1根时钟线和1根字选择信号线.基本的I2S连接具有一个主机(其总是为主机) ...
- displayport-2
上一章讲述了display-port的硬件连接,今天来说说协议层 图中可以看到,最底层是物理层,上层是连接服务层,提供的服务包括同步数据传输服务,aux链接服务,aux设备数据传输服务,在设备端也一样 ...
- NRF24L01无线通讯模块驱动
NRF24L01 无线模块,采用的芯片是 NRF24L01,该芯片的主要特点如下: )2.4G 全球开放的 ISM 频段,免许可证使用. )最高工作速率 2Mbps,高校的 GFSK 调制,抗干扰能力 ...
- iOS tableViewCell plane格式下,接近section边缘不显示分割线却被复用解决办法
今天做公司产品的时候遇到了如题问题,困扰我很长时间,用尽各种办法不能解决,究其原因不知为何,自定义cell低端有view划线的时候,划线一般的显示1像素,而贴着section的显示很少 顶多0.3像素 ...
- iOS开发笔记 - 界面调试神器Reveal
http://blog.csdn.net/jackfrued/article/details/50934092 Reveal是iOS开发工具中的神器之一,它能够在应用程序运行过程中调试应用程序 ...