管理Java类文件

来源:互联网 发布:2016网络流行语排行榜 编辑:程序博客网 时间:2024/06/05 19:11

在java中,每一个定义好的类,在编译的时候,都会对应地产生一个.class文件。如果程序的规模越来越大,那么类文件也会越来越多,管理起来也会越来越麻烦,很容易发生命名的冲突。因此,java中引入了"包"(package)的概念。


一、内部类

在类中还可以再定义类,这种类叫做内部类(Inner Class)。使用内部类主要有三个好处:一是可以任意地访问对应的外部类的私有(private)成员;二是如果一个内部类只服务于对应的外部类,那么外界就不必知道有这个内部类的存在;三是对于外部类来说,内部类可以将一系列数据类型“打包”,就像C++的类中再定义结构体一样。当然类的功能要比结构体强大多了。

1、访问外部类的prvate成员

import static java.lang.System.out;class Outer{    private int x = 0;        //内部类Inner    class Inner    {        public int accessOuter() //访问外部类的private成员        {            return x;        }    }        public Inner getInner() //返回内部类对象    {        return new Inner();    }        public static void main(String[] args)    {        Outer objOut = new Outer();        out.println(objOut.getInner().accessOuter());    }}


可以看到,程序打印出了外部类的private成员x的值。


2、将数据类型打包

public class InnerDemo{    //内部类Point,表示一个点    private class Point    {        private int x,y;                Point(int x,int y)        {            this.x = x;            this.y = y;        }        public String toString()        {            return "(x = " + x + ",y = " + y + ")";        }    }        //创建3个部类Point对象    Point[] pt = new Point[]{new Point(1,1),new Point(2,2),new Point(3,3)};        //输出点集    public void getAllPoints()    {        for(Point point : pt)        {            System.out.println(point);        }    }        public static void main(String[] args)    {        InnerDemo inner = new InnerDemo();        inner.getAllPoints();    }}
InnerDemo类表示一个点集,而点集中的每一个点元素就可以用内部类来定义表示。

程序运行结果:


对于一个包含内部类的类,程序编译后会产生一个名为 "外部类名$内部类名.class" 的类文件。如上例,编译后会生成InnerDemo$Point.class文件。由于Point类仅仅服务于其对应的外部InnerDemo类,因而在实际使用InnerDemo类的时候,我们不必关心Point类的存在。


二、匿名内部类

匿名内部类可以不用声明类名称,直接使用new关键字来产生一个对象:

new Object(){    public void doSomethig(){    //... ...    }}
这样的好处是,对于一些接口或者方法的参数类型是一个类的引用的时候,我们不必单独定义一个新的类去产生一个对象再把对象传进去,直接使用匿名内部类可以省略类的定义。如getInner方法需要一个Point类的对象,那么我们可以这样写:

getInner(new Point()    public void method()    {          //do something    });
值得注意的是,如果在一个匿名的内部类中想要访问外部的局部变量,那么就必须将这个要被访问的变量声明为final.否则在编译的时候就会报错,如:

public void method()    {        int x = 100; //没有声明为final        Object obj = new Object(){            public String toString()            {                System.out.println(x); //访问外部的x变量                return "New Object!";            }           };    }


那么,为什么编译器要强制我们把x声明为final?这是因为,在匿名内部类中访问x时,内部类中访问的只是变量x的一份拷贝,如果在匿名内部类中修改了变量x,那么这种修改是不会影响到外部的变量x的。所以把x声明为final后,就起到一个提醒的作用,表示程序员不可以在内部类中修改x的值。这样就降低了出错的可能性。



三、包(package),导入(import)

1、包

Java 提供包来管理类。包就对应着我们文件系统的文件目录。我们可以使用关键字 package来定义包,如:

package test;public class Point{}
编译时加入-d参数,并在后面指定要把生成的类放在哪一个文件之下,如:

javac -d . Point.java

这将会在当前目录下生成一个 test目录,Point.class文件就在这个test目录里。

注意,一旦设置了包后,这个包的名字就变成了类名的一部分。如上例,类Point的类名应为test.Point而不是Point了。


2、import

有时候我们的类的包名非常长,那么在使用的时候就会非常麻烦,因为要写上一长串包名。这时候就可以用import语句来导入一个包中的类,然后再使用此包中的类的时候,就不必加上长长的包名了。如:

不导入时:

test.Point pt = new test.Point();
使用import后:

import test.Point;//导入test包中的Point类Point pt = new Point();

编译器在编译这个源文件时,首先会在当前目录下寻找Point类文件,如果没有找到,就会试着组合import上的设置来寻找Point类。这样在使用类的时候就不需要加包名了。


但在使用import时,如果你把源文件跟生成的类文件都放在同一个目录,那么在编译时极可能会发生“找不到类”的错误。下面就是一个这样的例子:

我们在test目录下有这样两个文件:


假定在Point.class的上层目录里有这样一个程序:

import test.*;class ImportError{    Point pt = new Point();}

它使用通配符*导入了test目录下的所有类,但在编译时就会报错:


为什么会发生这个错误呢?

因为,当使用通配符*时,编译器就会导入test目录下的所有文件。当我们用到Point 类时,由于Point.java文件和Point.class文件都在test目录下,编译器会首先找到Point.java文件而不是Point.class类。所以会报错。

为了避免此类错误的发生,我们要把源文件跟类文件分开,专门建立一个src目录存放.java 文件,建立classes目录存放.class文件。


特别要说明的是,java.lang包是默认被自动导入的。


3、import静态成员

在J2SE 5.0后增加了import static 语法,允许我们导入一个类或接口中的静态成员。这样就可以让程序员写得更少了。如:

System.out.println("");

可以写成:

import static java.lang.System.out;...out.println("");...



嗯嗯,就先到这吧。。


原创粉丝点击