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 ...
随机推荐
- tensorflow的Virtualenv安装方式安装
本文介绍了如何在ubuntu上以virtualenv方式安装tensorflow. 安装pip和virtualenv: # Ubuntu/Linux 64-bit sudo apt-get insta ...
- Apache2 三种MPM对比分析
就最新版本的Web服务器Apache(版本是Apache 2.4.10,发布于2014年7月21日)来说,一共有三种稳定的MPM(Multi-Processing Module,多进程处理模块)模式. ...
- PHP操作mysql类
<?php class Mysql{ //数据库连接句柄 private $link; //返回结果集 private $result; //返回查询数据 private $data; //执行 ...
- hibernate---一级缓存, 二级缓存, 查询缓存
缓存: 内存开辟一块空间,把本来存在硬盘的东西放在内存里, 以后从内存读取. 一级缓存: session级别的缓存, session.load 二级缓存: 总的缓存.
- #Pragma Pack(n)与内存分配
#pragma pack(n) 解释一: 每个特定平台上的编译器都有自己的默认"对齐系数"(也叫对齐模数).程序员可以通过预编译命令#pragma pack(n),n=1,2,4, ...
- iOS开发——UITableView(未完,待续...)
1.让tableview的自定义cell,自动计算高度. self.tableView.estimatedRowHeight = 44.0; self.tableView.rowHeight = UI ...
- bzoj1070 修车&& bzoj2879美食节 【费用流】
bzoj1070: 把每个工人拆成汽车那么多个点,假如说 工人(i, j) 和 汽车k 连边,那就代表第i个工人倒数第j个修汽车k,那么这条边对以后的贡献就是k*time[i修k]. #include ...
- SVN下载分支、合并分支
http://www.cnblogs.com/armyfai/p/3985660.html(不知道实际工作中怎么使用,有好多步骤感觉不是太理解) 从远处把库fork到本地,会有一个库文件夹 服务器库结 ...
- Swoole:重新定义PHP
Swoole PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异 ...
- 对js原型对象的拓展和原型对象的重指向的区别的研究
我写了如下两段代码: function Person(){} var p1 = new Person(); Person.prototype = { constructor: Person, name ...