Java 第23 章 : 包的定义及使用

课时101:包的定义

        在实际的项目开发过程中,肯定要一直存在包的概念,利用包可以实现类的包装,在以后的实际开发之中,所有的类都必须放在包里面。

  • 包的定义与使用

        对于项目而言,尤其是现代的项目是不可能一个人开发完成的,往往在一个项目的开发团队之中会有2-3位的开发者进行项目业务的实现,于是在这样的情况下就不得不去面对一个问题:有可能产生类的重名定义。

        在操作系统之中已经明确严格的定义了一个要求:同一个目录之中不允许存放有相同的程序类文件,但是在实际的开发之中很难保证类的不重复,所以为了可以进行类的方便管理,那么往往可以将程序文件放在不同的目录下,不同的目录之中是可以提供有相同文件的,二者目录就称为包。   包=目录。

范例:定义包

package cn.mldn.demo;  //定义包,其中.表示分割子目录(子包)
public class Hello{
    public static void main(String args[]){
        System.out.println("Hello World !");
    }
}

一旦程序开发之中出现有包,此时程序编译后的结果就必须将*.class文件保存在指定的目录之中,但是如果手工建立则非常的麻烦,那么此时最好的做法是可以进行打包处理:javac -d.Hello.java

  • “-d”:表示要生成目录,而目录的结构就是package定义的结构;
  • “.”:表示在当前所在的目录中生成程序类文件;

        在程序执行的时候一定要带着包执行程序类:java cn.mldn.demo.Hello,也就是说从此之后完整的类名称是“包.类”名称。

课时102:包的导入

        利用包的定义实际上就可以将不同的功能的类保存在不同的包之中,但是这些类彼此之间也会存在有互相调用的关系,那么在这个时候就需要使用import语句来导入其他包中的程序类。

范例:定义一个程序类“cn.mldn.util.Message”,这个类负责进行一个消息数据的获取

package cn.mldn.util;
public class  Message{
    public String getContent(){
        return "www.mldn.cn";
    }
}

范例:定义一个测试类使用Message类“cn.mldn.test.TestMessage”。

package cn.mldn.test;
import cn.mldn.util.Message;  //导入其它包的类
public class TestMessage{
	public static void main(String args[]){
		Message msg = new Message(); //实例化对象
        System.out.println(msg.getContent());
	}
}

        此时按照使用顺序来讲肯定要先编译Message.java,而后再编译TestMessage.java,但是你思考一个问题,如果此时你写了一个程序代码,里面有100个类,彼此之间互相引用严格,此时你怎么区分?那么这时候最好的做法不是区分顺序,而是直接交给Java自己完成,编译的命令:javac -h . *.java

        注意:关于public class 与 class定义的区别?

  • public class :类名称必须与文件名称保持一致,一个*.java文件里面只允许有一个public class,同时如果一个类需要被其他的包所使用,那么这个类一定要你定义为public class文件,但是这些类只能被本包所访问,外包无法访问。
  • class:类名称可以与文件名称不一致,并且在一个*.java文件里面可以提供有多个class定义,编译后将形成不同的*.class
  • 在实际的开发之中往往在一个*.java源码文件里面只会提供有一个程序类,而这个程序类一般都使用public class定义,程序类中定义的包名称必须采用小写字母的形式定义,例如:cn.mldn.util;

        但是这个时候会有一个新的问题产生了,有些时候可能会使用某一个包中的很多类,于是这样分开进行类的导入会比较麻烦,为了解决这样的问题,也可以使用通配符“*”来处理。

package cn.mldn.test;
import cn.mldn.util.*;  //导入其它包的类
public class TestMessage{
	public static void main(String args[]){
		Message msg = new Message(); //实例化对象
        System.out.println(msg.getContent());
	}
}

        即便此时使用了“包.*”的导入形式,那么也不表示进行全部的加载,它会根据自己的需要加载所需要的程序类,而不需要的程序类是不会被加载的,所以是使用“*”还是使用具体的类,其最终的性能是完全相同的。

但是如果在开发之中采用的是“包.*”的形式进行包的导入时,那么有一点会比较麻烦:有可能两个不同的包中存在有相同的类名称,例如,现在假设TestMessage类由于某种需要,要导入两个包:cn.mldn.util、orz.demo,但是这两个包里面都有Message类。

 

        由于某种需要在TestMessage类里面导入了两个包:

package cn.mldn.test;
import cn.mldn.util.*;  //导入其它包的类
import org.demo.*;  //导入其它包的类
public class TestMessage{
	public static void main(String args[]){
		Message msg = new Message(); //实例化对象
        System.out.println(msg.getContent());
	}
}
cn.mldn.util.Message:org.demo.Message:
package cn.mldn.util;
public class  Message{
    public String getContent(){
        return "www.mldn.cn";
    }
}
package org.demo;
class  Message{
    public String getInfo(){
        return "人民万岁!";
    }
}
程序编译:javac -d.TestMessage.java

  org.demo 中的类 org.demo.Message和cn.mldn.util中的类cn.mldn.util.Message都匹配TestMessage.java:6: 错误:对Message的引用不明确

            Message msg = new Message(); //实例化类对象

org.demo中的类org.demo.Message 和 cn.mldn.util中的类cn.mldn.util.Message都匹配2个错误

这个时候就会发现类名称相同的时候就会出现不明确的引用处理,所以此时最简单的处理形式就是直接写上类的完整名称

 

 

package cn.mldn.test;
import cn.mldn.util.*;  //导入其它包的类
import org.demo.*;  //导入其它包的类
public class TestMessage{
    public static void main(String args[]){
        cn.mldn.util.Message msg = new cn.mldn.util.Message(); //实例化对象
        System.out.println(msg.getContent());
    }
}


在日后的开发过程之中经常会见到大量的重名的类(包不重名),此时为了更好地解决问题,往往会使用类的完整名称。

 

课时103:静态导入

假如说现在有一个类,这个类中的全部方法都是static方法,那么按照原始的做法肯定要导入程序所在的“包.类”。而后才可以通过类名称调用这些静态方法;

范例:定义一个MyMath数学类

package cn.mldn.util;

public class MyMath {
    public static int add(int... args) {
        int sum = 0;
        for (int temp:args) {
            sum += temp;
        }
        return sum;
    }

    public static int sub(int x, int y) {
        return x - y;
    }
}

        如果此时按照原始的方式进行处理,那么此时就需要导入包.类,而后通过类名称调用方法。

范例:原始方法使用

package cn.mldn.test;

import cn.mldn.util.MyMath;

public class TestMath {
    public static void main(String args[]) {
        System.out.println(MyMath.add(10, 20, 30));
        System.out.println(MyMath.sub(30, 20));
    }
}

从JDK1.5开始,对于类中全部由静态方法提供的特殊类,是可以采用静态导入处理形式的。

范例:静态导入处理

package cn.mldn.test;

import static cn.mldn.util.MyMath.*;

public class TestMath {
    public static void main(String args[]) {
        System.out.println(add(10, 20, 30));
        System.out.println(sub(30, 20));
    }
}

         当使用静态导入处理之后就好比该方法是直接定义在主类中的,可以有主方法直接调用。

课时104:生成jar文件

  • Jar命令

当一个项目开发完成之后一定会存在大量的*.class文件,那么对于这些文件的管理,往往可以利用一种压缩结构的形式来进行处理,而这样的结构在Java之中就被称为jar文件,如果要想将程序打包为Jar文件,那么可以直接利用JDK中提供的jar命令完成。

        在最原始的时候如果想要知道jar命令的时候直接输入jar即可,而在JDK1.9之后为了统一化,所以需要使用“ --help”查看相关的说明。

        下面通过程序的具体演示来实现jar的使用与配置操作。

1、定义一个程序类,这个类的代码如下:

package cn.mldn.util;

public class Message {
    public String getContent(){
        return "www.mldn.cn";
    }
}

2、对程序进行编译与打包处理:

  • 对程序打包编译:javac -d .Message.java;
  • 此时会形成cn的包,包里面又相应的子包与*.class文件,将其打包为mldn.jar:jar -cvf mldn.jar cn

        -  “-c”:创建一个新的jar文件;

        -  “-v”:得到一个详细输出;

        -  “-f”:设置要生成的jar文件名称,本处定义的是“mldn.jar”;

3、每一个*3.jar文件都是一个独立的程序路径,如果要想在java程序之中使用此路径,则必须通过CLASSPATH进行配置:

SET CLASSPATH=.;d:\mldndemo\mldn.jar

4、建立测试类,直接导入Message类并且调用方法:

package cn.mldn.test;
public class TestMessage{
    public static void main(String args[]){
         cn.mldn.util.Message msg = new cn.mldn.util.Message();  //实例化对象
         System.out.println(msg.getContent());
      }
    }

        随后就可以正常编译TestMessage类并且可以使用这个类:

  • 编译程序类:javac -d .Message.java;
  • 解释程序类:java cn.mldn.test.TestMessage。

         如果此时程序编译通过之后,但是由于CLASSPATH发生了改变,类无法加载到了,则执行TestMessage类的时候将会出现如下的错误提示:Exception in thread "main" java.lang.NoClassDefFoundError: cn/mldn/util/Message

         出现这种错误只有一种情况:*.jar包没有配置正确。

JDK1.9之后出现的模块化操作

  • 在JDK1.9以前所有的历史版本之中实际上提供的是一个所有类的*.jar文件(rt.jar、tools.jar),在传统的开发之中只要启动了Java虚拟机,那么就需要加载这几十兆的类文件;
  • 在JDK1.9之后提供了一个模块化的设计,将原本很大的一个要加载的一个*.jar文件变成了若干个模块文件,这样在启动的时候可以根据程序需要加载指定的模块(模块中有包),就可以实现启动速度变快的效果。

课时105:系统常用包

        Java语言从发展至今一直提供有大量的支持类库,这些类库一般由两个方面组成:

  • Java自身提供的(除了JDK提供的类库之外还会有一些标准);
  • 由第三方厂商提供的Java的支持类库,可以完成各种你需要的功能,并且支持的厂商很多;

而在JDK之中也会提供有大量的类库,并且这些类库都是封装在不同的开发包之中

  • java.lang:像String、Number、Object等类都在这个包里面,在这包在JDK1.1之后自动默认导入;
  • java.lang.reflect:反射机制处理包,所有的设计从此开始;
  • java.util:工具类的定义,包括数据结构的定义;
  • java.io:进行输入与输出流操作的程序包;
  • java.net:网络程序开发的程序包;
  • java.sql:进行数据库编程的开发包;
  • java.applet:Java的最原始的使用形式,直接嵌套在网页上执行的程序类;

        |-   现在的程序已经以Application为主了(有主方法的程序);

  • java.awt、javax.swing:Java的图形界面开发包(GUI),其中awt属于重量级的组件,而swing是轻量级的组件;

课时106:访问控制权限

        在面向对象的开发过程之中有三大主要特点:封装、继承、多态。那么对于封装性而言主要的实现依靠的就是访问控制权限,而访问控制权限在程序之中一共定义有四种:private、default(不写)、protected、public,这四种权限的作用如下。

No.访问范围privatedefaultprotectedpublic
1同一包中的同一类
2

同一包中的不同类

 
3不同包的子类  
4不同包的所有类   

        在整个访问控制权限的处理之中,只有protected(受保护)的权限是比较新的概念,下面对这一访问权限的使用进行说明,本次定义两个大类:

  • cn.mldn.a.Message类:提供有protected访问权限;
  • cn.mldn.b.NetMessage类:将直接访问protected属性;

范例:定义Message类

package cn.mldn.a;

public class Message {
    protected String info = "www.mldn.cn";
}

范例:定义子类,与父类不在同一个包中

package cn.mldn.b;

import cn.mldn.a.Message;

public class NetMessage extends Message {
    public void print() {
        System.out.println(super.info);
    }
}

范例:编写测试类,通过子类实现操作

package cn.mldn.test;

import cn.mldn.b.*;
import cn.mldn.b.NetMessage;

public class TestMessage {
    public static void main(String args[]) {
        new NetMessage().print();
    }
}

此时的程序是通过子类访问父类中的protected属性。但是如果说此时你直接通过了Message访问info属性,那么就将出现错误的提示。

范例:在测试类中直接访问Message

package cn.mldn.test;

import cn.mldn.a.*;


public class TestMessage {
    public static void main(String args[]) {
        System.out.println(new Message().info);
    }
}
java: info 在 cn.mldn.a.Message 中是 protected 访问控制

        在程序之中的封装一共有三个对应的访问权限:private、default、protected,但是如果每次在使用的时候进行区分会比较麻烦,所以可以给出一个参考的选择方案(90%的设计问题):

  • 只要是进行属性的定义,全部使用private;
  • 只要是进行方法的定义,全部使用public。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值