第八章 包和内部类

类除了具有普通的特性,还具有一些高级特性, 如包、内部类等。包在整个管理过程中起到了非 常重要的作用,使用包可以有效地管理繁杂的类文件,解决类重名的问题。在类中应用包与权限修饰符,可以控制其他人对类成员的访问。

Java 中还有 一个更为有效的隐藏实现细节的方式,那就是使用 内部类,通过后可以向上转型为被内部类实现的公共共接口。由于在类中可以定义多个内部类,实现接口的方式也不止一个,因此只要将内部类中的方法设设置为类最小范围的修饰权限,即可将内部类的实现细节有效地隐藏。
2bf76e5e6dd44617aeda1b815f9ea5cf.png

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

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

(2)完整的类路径
编写Java程序经常用到String类(第10章会详细讲解),其实 String 类并不是它的完整名称,就如同一个人需要有名有姓一样, String类的完整名称如图81所示。可以看出,一个完整的类名需要包名与类名的组合,每个类都隶属于一个类包,只要保证同一类包中的类不同名,就可以有效地避免同名类冲突的情况。

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

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

java.util.Date date=new java.util.Date();

java.sql.Date date2=newjava.sqlDate(1000);

 da6c63eba4824698bea275ea36e34be5.png

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

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

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

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

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

在 Java中包名设计应与文件系统结构相对应,如一个包名为commr,那么该包中的类位于com文件夹下的mr子文件夹下。没有定义包的类会被归纳在默认包(default package)中。在类中定义包名的语法如下:

package 包名

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

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

【例8.1】创建自定义的Math类

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

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

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

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

import com.mrMath //导入commr包中的Math类 

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

2.使用import导入静态成员
import关键字除导入包外,还可以导入静态成员 这是JDK5.0以上版本提供的功能。导入静态成 

员可以使编程更为方便。使用import导入静态成员的语法如下:

import static 静态成员

【例8.2】使用Import导入静态成员

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

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

二、内部类
内部类(Inner Class),是 Java 中对类的一种定义方式,是嵌套类的一个分类,即非静态嵌套类(Non-Static Nested Class)。内部类(非静态嵌套类)分为成员内部类、局部内部类和匿名内部类三种。

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

class OuterClass//外部类

          class InnerClass{//内部类

  }

}

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

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

c6ea296730c6491db30c04d4d214fdd2.png

【例8.3】使用成员内部类模拟发动机点火

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

f45c33c1302947a7ada293d6fbfa03a8.png

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

外部类 outer=new 外部类();

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

注意:

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

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

2.使用this关键字获取内部类与外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this 关键字。【例8.4】在内部类中调用外部类对象

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

 

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

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

new 父类/父接口()}

       子类实现的内容

};

注意:

最后一个大括号之后有分号。

【例8.5】使用匿名内部类创建一个抽象狗类的对象

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

972fc3936c084a8aa494eccb60ebc707.png 

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

匿名类不能写构造方法。

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

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值