Java第八章包和内部类

文章介绍了Java中的类包机制,如何解决类名冲突,以及如何创建和使用类包。类包通过包名和类名的组合避免了命名冲突,方便管理大量类。此外,文章还详细讲解了内部类,包括成员内部类和匿名内部类的使用,强调了内部类可以直接访问外部类的私有成员,并展示了如何在外部类和其他类中创建和使用内部类对象。
摘要由CSDN通过智能技术生成

一、Java类包

        在Java中每定义好一个类,通过Java编译器进行编译之后,都会生成一个扩展名为.class的文件。当程序的规模逐渐扩大时,就很容易发生类名冲突的现象。jdk apl中提供了成千上万具有各种功能的类,java中提供了一种管理类文件的机制,就是类包。

1.类名冲突

        Java中每个接口或类都来自不同的类包,无论是Java API中的类与接口还是自定义的类与接口,都需要隶属于某一个类包,这个类包包含了一些类和接口。如果没有包的存在,管理程序中的类名称将是一件非常麻烦的事情。如果程序只由一个类组成,自然不会出现类名重叠的问题,但是随着程序的类的数量增多,难免会出现这一问题。例如, 在程序中定义一个Login 类,因业务需要,还要定义 一个名称为Login的类,但是这两个类所实现的功能完全不同,于是问题就产生了--编译器不会允许存在同名的类文件。解决这类问题的办法是将这两个类放置在不同的类包中。

2.完整的类路径

        编写java程序经常用到String类,其实String类并不是它的完整名称,就如同一个需要有名有姓一样,String类的完整名称如下图所示,可以看出,一个完整的类名需要包名与类名的组合,每个类都隶于属于一个类包,只要保证同一类包中的类不同,就可以有效地避免同名类冲突的情况。

        例如,一个程序中同时使用到 javautil.Date 类与java.sql.Date类,如果在程序中不指定完整的类路径,编译器不会知道这段代码使用的是java.util类包中的Date类还是javasql类包中的Date类,所以需要在指定代码中给出完整的类路径。

        例如,在程序中使用两个不同Date类的完整类路径可以使用如下代码:

java.util.Date date = new java.util.Date();
java.sql.Date date2 = new java.sql.Date(1000);

        在Java中采用类包机制非常重要,类包不仅可以解类名冲突问题,还可以在开发庞大的应用程序时,帮助开发人员管理庞大的应用程序组件,方便软件复用。下面来看一下在 Java中如何创建类包(以下简称包)。

说明:同一包中的类相互访问时,可以不指定包名。

3.创建包

        在Eclipse中创建包的步骤如下:

        (1)在项目的src节点上右击,选择“新建”/“包”命(英文为New/Package)。

        (2)弹出“新建Java包”(NewJava Package)对话,在“名称”(Name) 文本框中输入新建的包名,如com.mr,然后单击“完成”(Finish)按钮,如下图所示。


        (3)在Eclipse中创建类时,可以在新建立的包上右击,选择“新建”(New)命令,这样新建的类会默认保存在该包中。另外也可以在 New Java Class对话框中指定新建类所在的包。

        在Java中包名设计应与文件系统结构相对应,如一个包名为com.mr,那么该包中的类位于com文件夹下的mr子文件夹下。没有定义包的类会被归纳在默认包(default package)中。在实际开发中,应该为所有类设置包名,这是良好的编程习惯。在类中定义包名的语法如下:

package 包名

        在类中指定包名时,需要将package表达式放置在程序的第一行,它必须是文件中的第一行非注释代码。使用package关键字为类指定包名之后,包名将会成为类名中的一部分,预示着这个类必须指定全名。例如,在使用位于com.mr包下的Dog.java类时,需要使用形如com.mr.Dog这样的表达式。

        注意:Java包的命名规则是全部使用小写字母。

        例题:创建自定义的Math类

        在项目中创建Math类,在创建类的对话框中指定包名为com.mr,并在主方法中输出说明该类并非java.lang包中的Math类。

 本实例中,在程序的第一行指定包名,同时在com.mr包中定义Math类。java类包中提供了java.lang.Math类,而本实例定义的为com.mr.Math类,可以看出在不同包中定义相同类名也是没有问题的,所以在Java中使用包可以有效管理各种功能的类。

4.导入包
        (1)使用import关键字导入包
如果某个类中需要使用 Math 类,那么如何告知编译器当前应该使用哪一个包中的 Math 类,是java.lang.Math 类还是com.mr.Math 类?这是一个令人困扰的问题。此时,可以使用Java 中的import关键字指定。例如,如果在程序中使用import 关键字导入 com.mr.Math类,在程序中使用Math类时就会自动选择com.mr.Math类。import 关键字的语法如下:

import com.mr.*;    //导入 com.mr 包中的所有类

import com.mr.Math    //导入 com.mr 包中的Math 类

在使用import关键字时,可以指定类的完整描述,如果为了使用包中更多的类,可以在使用import关键字指定时在包指定后加上*,这表示可以在程序中使用该包中的所有类。

        注意:
        如果类定义中已经导入 com.mr.Math 类,在类体中再使用其他包中的 Math 类时就必须指定完整的带有包格式的类名。例如,在上述情况下再使用 java.lang 包的Math 类时就要使用全名格式java.lang.Math。

        在程序中添加 import 关键字时,就开始在 CLASSPATH 指定的目录中进行查找,查找子目录com.mr,然后从这个目录下编译完成的文件中查找是否有名称符合者,最后寻找到Math.class 文件另外,当使用import 指定了一个包中的所有类时,并不会指定这个包的子包中的类,如果用到这个包的子包中的类。需要再次对子包进行单独引用。

        (2)使用import导入静态成员
import关键字除导入包外,还可以导入静态成员,这是JDK5.0以上版本提供的功能。导入静态成员可以使编程更为方便。使用import导入静态成员的语法如下:

import static 静态成员

        例题:使用Import导入静态成员

        在项目中创建ImportTest类,在该类中使用import关键字导入静态成员。

 从本实例中可以看出,分别使用import static 导入了 java.lang.Math类中的静态成员方法max()和java.lang.System类中的out成员变量,这时就可以在程序中直接引用这些静态成员,如在主方法中直接使用out.println()表达式以及max()方法。

二、内部类

        在一个文件中定义两个类,则其中任何一个类都不在另一个类的内部。如果在类中再定义一个类,则将在类中在定义的那个类称为内部类。成员内部类和匿名类为最常见的内部类。

1.成员内部类

        (1)成员内部类简介

        在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。成员内部类的语法如下:

class OuterClass{        //外部类
    class lnnerClass{    //内部类
    }
}

        在成员内部类中可以随意使用外部类的成员方法及成员变量,尽管这些类成员被修饰为private。下图充分说明了内部类的使用,尽管成员变量i以及成员方法g()都在外部类中被修饰为private,但在成员内部类中可以直接使用。

        内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。内部类初始方式与其他类的初始化方式相同,都是使用new关键字。

        例子:使用成员内部类模拟发动机点火

        首先创建Car类,Car类中有私有属性brand和start()方法,然后在Car类的内部创建Engine类,Engine类中有私有属性model和ignite()方法,最后打印出“启动大众朗行,发动机EA211点火”。

         成员内部类不止可以在外部类中使用,在其他类中也可以使用。在其他类中创建内部类对象的语法非常特殊,语法如下:

外部类 outer = new 外部类();
外部类.内部类 inner = outer.new 内部类();

        注意:

        1.如果在外部类和非静态方法之外实例化内部类对象,需要使用“外部类.内部类”的形式指定该对象的类型。

        2.内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。

        (2)使用this关键字获取内部类与外部类的引用

        如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。

        例题:在内部类中调用外部类对象

        在项目中创建TheSameName类,在类中定义成员变量x,再定义一个内部类Inner,在内部类中也创建x变量,并在内部类的doit()方法中定义一个局部变量x。

         在类中,如果遇到内部类与外部类的成员变量重名的情况,可以使用this关键字进行处理。例如,在内部类中使用this.x语句可以调用内部类的成员变量x,而使用TheSameName.this.x语句可以调用外部类的成员·变量x,即使用外部类名称后跟一个点操作符和this关键字便可获取外部类的一个引用。

2.匿名内部类

        匿名类是只在创建对象时才会编写类体的一种写法。匿名类的特点是“现用现写”,其语法如下:

new 父类/父接口(){
    子类实现的内容
};

        注意:最后一个大括号之后有分号。

        例题:使用匿名内部类创建一个抽象狗类的对象

        创建一个抽象的狗类,类中有一个颜色的属性和两个抽象方法,在测试类的主方法中创建抽象类对象,并用匿名内部类实现该对象的抽象方法。

         从这个结果可以看出,本来无法创建对象的抽象类竟然也可以出现在new关键字的右侧。为何叫匿名内部类?就是因为实例Dog抽象类的实现类没有名称。创建出的对象maomao既不是金毛犬,也不是哈士奇犬,在程序中maomao只能解读为“一只具体的无名之狗”。使用匿名类时应该遵循以下原则:

        1.匿名类不能写构造方法。

        2.匿名类不能定义静态的成员。

        3.如果匿名类创建的对象没有赋值给任何引用变量,会导致该对象用完一次就会被java虚拟机销毁。

        说明:匿名内部类编译以后,会产生以“外部类名$序号”为名称的.class文件,序号以1~n排列,分别代表1~n个匿名内部类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Violet Evegarden

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值