目录
1、java包机制
作用:划分代码功能,方便程序的管理,对类进行一定的划分,易于管理和维护
语法:定义再程序的最前排,在程序的首行编写,并且只能有一句,因为类只会存在于一个包中
package 包名;
包名要全部小写,是标识符,要遵守标识符的命名规则。
回顾——标识符的命名规则
我们可以且有权利对其进行命名的都是标识符
- 可以是字母、数字、下划线 、$组成,不能含有其他的符号,包括空格也不可以,因为空格也是特殊字符。
- 不能以数字开头
- 严格区分大小写
- 关键字不能做标识符
- 理论上无长度限制,但是不要太长
标识符的命名规范【行内默认的规定】
- 起名要见名知意
- 驼峰命名法
- 类名、接口名:首字母大写,其后单词首字母大写
- 变量名、方法名:首字母小写,后面每个单词首字母大写
- 常量名:全部大写,如果有多个单词组成,单词和单词之间用下划线隔开
包名命名方式:公司域名倒序+项目名+模块名+功能名;
采用这种命名方式能够降低重名率,更加的直观,易于代码的组织管理。
结构:一个包对应一个目录,目录的各层级之间使用 “ · ”隔开。
2、域名倒序
例如,对于百度的网址 www.baidu.com,它的域名:baidu.com,那么域名的倒序就是com.baidu;
3、加入包机制后的编译和运行
注意加入了包机制之后,就相当于包名是姓氏,类名是名字,只有包名+类名才能够正确的表示当前类,所以真正的类名是全类名=包名+类名。
那么在编译和运行的时候【指令 +类名】中的类名应该是全类名。
例如代码如下所示:在包test中有一个类test05
package test;
public class test05 {
public static void main(String[] args) {
System.out.println("Die");
}
}
通过命令javac进行编译,然后如下运行,发现有报错,查询当前test05.java文件的路径为【D:\Idea\JAVATEST\src\test】,很明显,当前运行的路径没有错误,为什么无法运行呢?看test05类的代码,发现是有package语句的,所以这个类真正的名字是:包名 · 类名=test.test05。
D:\Idea\JAVATEST\src\test>javac test05.java
D:\Idea\JAVATEST\src\test>java test05
错误: 找不到或无法加载主类 test05
那么尝试对类名进行修改,运行后如下:很明显完成了输出操作。
D:\Idea\JAVATEST\src>java test.test05
Die
有命令:【javac -d 编译之后的路径 java源文件的路径】指将java源文件进行编译后生成的字节码文件放到“编译之后的路径”中
如上代码,执行如下:
D:\Idea\JAVATEST\src>javac -d D:\Idea\JAVATEST\src D:\Idea\JAVATEST\src\test05.java
test05.java的路径:D:\Idea\JAVATEST\src\test05.java
在编译之后,test05.class的路径就在D:\Idea\JAVATEST\src\test\test05.class
类加载的时候默认从当前路径下加载,所以先将路径切换到文件所在的路径,然后再运行,运行的时候,名字用全类名。
例如用idea进行代码的编写,如下:会报错
因为test05.java和test06.java不在同一个包中,所以在test05的文件中是找不到test06.java文件的,因为两个类的姓氏不一样。
所以应该用类的全称去进行实例化,如下所示:
package test01;
public class test06 {
public void sys(){
System.out.println("Die");
}
}
public class test05 {
public static void main(String[] args) {
test01.test06 test=new test01.test06(); //用全类名去实例化一个对象
test.sys();
}
}
输出结果:是可以实现正常输出的
Die
Process finished with exit code 0
4、包名的省略
如果两个类在同一个目录(包)下,就可以省略包名。例如同包下的两个java类(test06-test07):
test06.java:
package test01;
public class test06 {
public static void main(String[] args) {
test07 test07=new test07();
System.out.println(test07.i);
}
}
test07.java
package test01;
public class test07 {
int i=0;
}
运行结果:正常输出,没有错误或者异常
0
Process finished with exit code 0
否则不能省略,因为省略了包名之后,在寻找这个类的文件的时候,会在当前包中寻找,如果找不到会导致报错,如上文的示例(test05-test06)。
那么如果不在同一个包中,想要省略包名怎么办呢?import的关键字就出现了。
4、import关键字
那么问题就出现了,如果在我们进行代码编写的时候,利用全类名去进行代码的编写,十分的浪费时间,而且增加代码理解和阅读的复杂度。这种时候,我们就想要省略包名,简化代码的编写,那么导包的功能的出现就成为了必然。
关键字:import
语法:import 包名.类名或者通配符
作用:一次性导入其他包中的我们所需的类,这样在这个类中就可以使用导入的包中的类,不必用包名做前缀,省略包名,直接通过类名去创建对象,更加的快捷方便。
原理:import 只是请编译器帮你打字,让编译器把没有姓的类别加上姓,并不会把别的档案的代码写入进来。
注意:导包语句编写在包语句之下,class定义之上
特殊包:
其他包:需要手动的通过import关键字进行导入。
如下几行代码:
java.io.InputStream is = java.lang.System.in;
java.io.InputStreamReader isr= new java.io.InputStreamReader(is);
java.io.BufferedReader br = new java.io.BufferedReader(isr);
代码十分的繁琐,通过import语句导入上述代码中的包名们
import java.lang.System;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
代码就可以简化为如下,很明显代码已经简洁了很多。
InputStream = System.in;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
5、import导入分类
①单类型导入(single-type-import)
②按需类型导入(type-import-on-demand)
从名字就可以看出来,导入的是类型,不是源代码,它只是拜托编译器帮忙补充没有姓氏的那些类名。
导入的类或接口的简名(simple name)具有编译单元作用域.这表示该类型简名可以在导入语句所在的编译单元的任何地方使用.这并不意味着你可以使用该类型所有成员的简名,而只能使用类型自身的简名。例如: java.lang包中的public类都是自动导入的,包括Math和System类.但是,你不能使用简名PI()和gc(),而必须使用Math.PI()和System.gc().你不需要键入的是java.lang.Math.PI()和java.lang.System.gc().
编译器会自动导入 java.lang包,所以无需程序员手动的进行包的导入,如果重复导入了包怎么办呢?编译器会清楚冗余的导包声明。
注意按需类型导入的方式要适度应用,虽然不会影响代码的执行速度,但是它会影响代码的编译速度。
参考内容:
因为单类型导入和按需类型导入对类文件的定位算法是不一样的。
java编译器会从启动目录(bootstrap),扩展目录(extension)和用户类路径下去定位需要导入的类,而这些目录仅仅是给出了类的顶层目录【即包的上一级目录】。编译器的类文件定位方法大致可以理解为如下公式:
顶层路径名 \ 包名 \ 文件名.class = 绝对路径
对于单类型导入很简单,因为包明和文件名都已经确定,所以可以一次性查找定位。
但是对于按需类型导入则比较复杂,编译器会把包名和文件名进行排列组合,然后对所有的可能性进行类文件查找定位。例如代码的开头如下:
package com;
import java.io.*;
import java.util.*;
当你的类文件中用到了File类,那么可能出现File类的地方如下:
1、File \ File类属于无名包,就是说File类没有package语句,编译器会首先搜索无名包
2、com.File \ File类属于当前包
3、java.lang.File \编译器会自动导入java.lang包
4、java.io.File
5、java.util.File
需要注意的地方就是,编译器找到File类之后并不会停止下一步的寻找,而要把所有的可能性都查找完以确定是否有类导入冲突。假设此时的顶层路径有三个,那么编译器就会进行3*5=15次查找。
【对于如上的导入方式,可以发现有五种包名和文件名组合的方式,因为完整的路径是加上顶层的目录,即包的上一级目录,构成的一个绝对地址,所以以上五种情况,加上不同的顶层目录前缀,共有15种可能性】
了解以上原理之后,我们可以得出这样的结论:按需类型导入是绝对不会降低Java代码的执行效率的,但会影响到Java代码的编译速度,因为需要进行完整的匹配和筛选对比。
按需类型导入的缺点:
1)编译速度:在一个很大的项目中,它们会极大的影响编译速度.但在小型项目中使用在编译时间上可以忽略不计。
2)命名冲突:解决避免命名冲突问题的答案就是使用全名.而按需导入恰恰就是使用导入声明初衷的否定. (例如:当你import java.awt.;import java.util.后,使用List的时候编译器将会出编译错误),在idea中会存在自动优化,不需要得包也会优化掉。
3)说明问题:全名的使用更加的直白.毕竟高级语言的代码是给人看的,按需导入可能会导致代码的理解问题。
4)无名包问题:如果在编译单元的顶部没有包声明,Java编译器首选会从无名包中搜索一个类型,然后才是按需类型声明.如果有命名冲突就会产生问题。(例如:顶层目录为D:\test,这个路径下有一个test05.java文件和包A,我们想要的java文件所在的路径为:D:\test\A\B\test05.java,其全类名为:A.B.test05.java,在搜索的时候,会在两个路径都发现这个java文件,虽然在顶层路径中找到了,但是还是会扫描所有的可能路径,这样有可能会产生命名冲突问题,合理利用开发工具能够很大程度上避免一些错误或者及时发现错误,代码编写更加的高效,代码也会更加的优化)。
常用的包
Java.lang包:java的核心类库,包含了运行java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省(默认)加载这个包。
java.util包:Java的实用工具类库。在这个包中,Java提供了一些实用的方法和数据结构。例如,Java提供日期(Data)类、日历(Calendar)类来产生和获取日期及时间,提供随机数(Random)类产生各种类型的随机数,还提供了堆栈(Stack)、向量(Vector) 、位集合(Bitset)以及哈希表(Hashtable)等类来表示相应的数据结构。
java.io包:java语言的标准输入/输出类库,如基本输入/输出流、文件输入/输出、过滤输入/输出流等。
java.util.zip包:实现文件压缩功能。
java.lang.reflect包:提供用于反射对象的工具。
java.mah:如提供用于执行任意精度整数算法 (BigInteger) 和任意精度小数算法 (BigDecimal) 的类。
java.net包:用来实现网络功能的类库。如Socket类、ServerSocket类。
java.awt包:构建图形用户界面(GUI)的类库。提供的类如:低级绘图操作Graphics类,图形界面组件和布局管理如 Checkbox类、Container类、LayoutManager接口等,以及用户界面交互控制和事件响应,如Event类。
java.awt.event包:GUI事件处理包。
java.awt.image包:处理和操纵来自于网上的图片的java工具类库。
java.sql包:实现JDBC的类库。
java.applet包:编写java applet程序用的。
在大型工程中,一般的书写建议是:采用单类型引入,而且即使是同一个package下的,也要import,避免歧义得发生。
参考链接:
http://t.csdn.cn/8mHE0http://t.csdn.cn/8mHE0https://blog.csdn.net/qq_37958652/article/details/89222042http://xn--uir93xlrs/