Java使用package解决类名冲突 一个类总是属于某个包,真正的完整类名是包名.类名 在定义class的时候,我们需要在第一行声明这个class属于哪个包。
小明的Person.java文件:
package ming; // 申明包名ming
public class Person { }
包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系 没有定义包名的class,它使用的是默认包,非常容易引起名字冲突,因此,不推荐不写包名的做法。 按照包结构把java文件组织起来,例如(ming,hong,mr.jun都是包) 所有的Java文件对应的目录层次要和包的层次一致 编译后的.class文件也需要按照包结构存放。如果使用IDE,把编译后的.class文件放到bin目录下,那么,编译的文件结构就是: 编译的命令相对比较复杂,我们需要在src目录下执行javac命令: javac -d ../bin ming/Person.java hong/Person.java mr/jun/Arrays.java 在IDE中,会自动根据包结构编译所有Java源码,所以不必担心使用命令行编译的复杂命令。
位于同一个包的类,可以访问包作用域的字段和方法。不用public、protected、private修饰的字段和方法就是包作用域。例如,Person类定义在hello包下面:
package hello; public class Person { // 包作用域: void hello() { System.out.println("Hello!"); } }Main类也定义在hello包下面
package hello; public class Main { public static void main(String[] args) { Person p = new Person(); p.hello(); // 可以调用,因为Main和Person在同一个包 } }在一个class中引用其他的class的方法:
直接写出完整类名(太麻烦不推荐) // Person.java package ming; public class Person { public void run() { mr.jun.Arrays arrays = new mr.jun.Arrays(); } } 使用import语句 // Person.java package ming; // 导入完整类名: import mr.jun.Arrays; public class Person { public void run() { Arrays arrays = new Arrays(); } }可以使用import mr.jun.* 导入mr.jun包的所有class,但是不推荐 寻找class Java编译器最终编译出的.class文件只使用完整类名,因此,在代码中,当编译器遇到一个class名称时: 如果是完整类名,就直接根据完整类名查找这个class; 如果是简单类名,按下面的顺序依次查找: 查找当前package是否存在这个class; 查找import的包是否包含这个class; 查找java.lang包是否包含这个class。 如果按照上面的规则还无法确定类名,则编译报错。
编写class的时候,编译器会自动帮我们做两个import动作: 默认自动import当前package的其他class; 默认自动import java.lang.*。 一个工程项目的文件结构 注意,包名必须完全一致,包没有父子关系,com.apache和com.apache.abc是不同的包。
如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。
把方法定义为package权限有助于测试,因为测试类和被测试类只要位于同一个package,测试代码就可以访问被测试类的package权限方法。
一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。
Java内建的访问权限包括public、protected、private和package权限;
Java在方法内部定义的变量是局部变量,局部变量的作用域从变量声明开始,到一个块结束;
final修饰符不是访问权限,它可以修饰class、field和method;
一个.java文件只能包含一个public类,但可以包含多个非public类。
public、protected、private三者修饰的类的成员访问作用域如下 上表中的默认就是指没有修饰符修饰
定义为public的class、interface可以被其他任何类访问:(导包上面说过了,class和interface一般都定义成public,不然干啥???)
定义在一个class内部的class称为嵌套类(nested class),Java支持好几种嵌套类。
Inner Class除了有一个this指向它自己,还隐含地持有一个Outer Class实例,可以用Outer.this访问这个实例。所以,实例化一个Inner Class不能脱离Outer实例。
下面的程序在控制台分别输出:30,20,10
匿名类也是一种定义Inner class的方法,且不需要再Outer class中明确定义这个class,而是在方法内部,通过匿名类来定义,示例代码如下
public class Main { public static void main(String[] args) { Outer outer = new Outer("Nested"); outer.asyncHello(); } } class Outer { private String name; Outer(String name) { this.name = name; } void asyncHello() { Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello, " + Outer.this.name); } }; new Thread(r).start(); } }观察asyncHello()方法,我们在方法内部实例化了一个Runnable。Runnable本身是接口,接口是不能实例化的,所以这里实际上是定义了一个实现了Runnable接口的匿名类,并且通过new实例化该匿名类,然后转型为Runnable。在定义匿名类的时候就必须实例化它,定义匿名类的写法如下: Runnable r = new Runnable() { // 实现必要的抽象方法… }; 匿名类和Inner Class一样,可以访问Outer Class的private字段和方法。之所以我们要定义匿名类,是因为在这里我们通常不关心类名,比直接定义Inner Class可以少写很多代码。
用static修饰的内部类和Inner Class有很大的不同,它不再依附于Outer的实例,而是一个完全独立的类,因此无法引用Outer.this,但它可以访问Outer的private静态字段和静态方法。如果把StaticNested移到Outer之外,就失去了访问private的权限。
小结 Java的内部类可分为Inner Class、Anonymous Class和Static Nested Class三种: Inner Class和Anonymous Class本质上是相同的,都必须依附于Outer Class的实例,即隐含地持有Outer.this实例,并拥有Outer Class的private访问权限; Static Nested Class是独立类,但拥有Outer Class的private访问权限。
不要设置classpath!对大多数情况编译器能够找到class路径,IDE也可以帮助解决,不必多此一举。
在大型项目中,不可能手动编写MANIFEST.MF文件,再手动创建zip包。Java社区提供了大量的开源构建工具,例如Maven,可以非常方便地创建jar包。
JVM通过环境变量classpath决定搜索class的路径和顺序;
不推荐设置系统环境变量classpath,始终建议通过-cp命令传入;
jar包相当于目录,可以包含很多.class文件,方便下载和使用;
MANIFEST.MF文件可以提供jar包的信息,如Main-Class,这样可以直接运行jar包。
Java 9引入的概念 廖雪峰老师关于模块的讲解