java语法基础-java面向对象编程-包的定义及使用
包的定义
在实际的项目开发过程之中,肯定要一直存在有包的概念,利用包可以实现类的包装,在以后的实际开发之中,所有的类都必须放在包里面
对于项目而言,尤其是现代的项目是不可能一个人开发完成的,往往在一个项目的开发团队之中会有2-3位的开发者进行项目业务的实现,于是在这样的情况下就不得不去面对一个问题:有可能产生类的重名定义
在操作系统之中已经明确严格的定义了一个要求:同一个目录之中不允许存放有相同的程序类文件,但是在实际的开发之中很难保证类的不重复,所以为了可以进行类的方便管理,那么往往可以将程序文件放在不同的目录下,不同的目录之中是可以提供相同文件的,而这个目录就成为包。包 = 目录
package cn.mldn.demo; // 定义包,其中.表示分割子目录(子包) public class Hello{ public static void main(String args[]){ Syetem.out.println("Hello World"); } }
一旦程序开发之中出现有包,此时程序编译后的结果就必须将.class文件保存在指定的目录之中,但是如果手工建立则非常的麻烦,那么此时最好的做法是可以进行打包编译处理:javac -d . Hello.java*
- "-d" :表示要生成目录,而目录的结构就是package定义的结构
- "." : 表示在当前所在的目录中生成程序类文件
在程序执行的时候一定要带着包执行程序类:java cn.mldn.demo.Hello,也就是说从此之后完整的类名称是"包.类名称"
在以后开发中,必须有包,必须放在首行
包的导入
利用包的定义实际上就可以将不同功能的类保存在不同的包中,但是这些类彼此之间一定会存在有互相调用的关系,那么在这个时候就需要使用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()); } }
此时按照使用顺序来讲肯定要先编译TestMessage.java,但是你思考一个问题,如果你现在写了一个程序代码,里面有100个类,彼此之间互相引用严格,此时你怎么区分?那么这个时候最好的做法不是区分顺序,而是直接交给Java自己完成,编译的命令:
javac -d . *.java java cn.mldn.test.TestMessage
注意:关于public class于class定义的区别?
-
public class :类名称必须于文件名称保持一致,一个 .java文件里面只允许有一个public class,同时如果一个类需要被其他的包所使用,那么这个类一定要定义为public class
-
class: 类名称可以与文件名称不一致,并且在一个.java文件里面可以提供有多个class定义,编译后将形成不同的.class文件,但是这些类只能够被本包所访问,外包无法访问**
-
在实际的开发之中往往在一个.java源代码里面只会提供有一个程序类,而这个程序类一般都使用public class定义*
程序类中定义的包名称必须采用小写字母的形式定义,例如:cn.mldn.util
但是这个时候会有一个新的问题产生,有些时候可能会使用某一个包中的很多类,于是这样分开进行类的导入比较麻烦,为了解决这样的问题,也可以使用通配符来处理*
即便此时使用了"包."的导入形式,那么也不表示要全部的加载,它会根据自己的需要加载所需要的程序类,而不需要的程序类是不会被加载的,所以是使用"",还是使用具体的类其最终的性能是完全相同的**
import cn.mldn.util.* ;
但是如果在开发之中采用的是"包."的形式进行包的导入时,那么有一点会比较麻烦:有可能两个不同的包中存在有相同的类名称*,例如:现在假设TestMessage类由于某种需要导入两个包:cn.mldn.util,org.demo,但是这两个包里面都有Message类
package cn.mldn.util; public class Message{ public String getContent(){ return "www.mldn.cn"; } }
package org.demo; public class Message{ public String getInfo(){ return "www.xxxx.cn"; } }
由于某种需要在TestMessage类里面导入了两个包
//org.demo 中的类 org.demo.Message 和 cn.mldn.util 中的类 cn.mldn.util.Message 都匹配
类名称相同的时候就会出现不明确的引用处理,所以此时最简单的处理形式就是直接写上类的完整名称
package cn.mldn.test ; import cn.mldn.util.Message ; // 导入其他包的类 public class TestMessage{ public static void main(String args[]){ cn.mldn.util.Message msg = new cn.mldn.util.Message();// 实例化对象 System.out.println(msg.getContent()); } }
在日后的开发过程之中经常会见到大量的重名的类(包不重名),此时为了更好的解决问题,往往会使用类的完整名称进行操作
静态导入
假如说现在有一个类,这个类中的全部方法都是static方法,那么按照原始的做法肯定要导入程序所在的"包.类"。而后才可以通过类名称调用这些静态方法
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.* ; // 导入其他包的类 public class TestMath{ public static void main(String args[]){ System.out.println(MyMath.add(1,2,3)); System.out.println(MyMath.sub(3,2)); } }
从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(1,2,3)); System.out.println(sub(3,2)); } }
当使用了静态导入处理之后就好比该方法是直接定义在主类中的,可以由主方法直接调用
生成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.对程序进行编译与打包处理
1. 对程序打包编译:javac -d . Message.java 2. 此时会形成cn的包,包里面会有相应的子包与*.class文件,将其打包为mldn.jar : jar -cvf mldn.jar cn "-c" :创建一个新的jar文件 "-v":得到一个详细输出 "-f":设置要生成的jar文件的名称,本处定义的是"mldn.jar"
3.每一个.jar文件都是一个 独立的程序路径,如果要想在Java程序之中使用此路径,则必须通过CLASSPATH进行配置*
SET CLASSPATH=.;C:\Users\wang\Desktop\demo.mldn.jar
程序解释执行的时候要通过CLASSPATH加载类
4.建立测试类,直接导入
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 . TestMessage.java
- 解释程序:java cn.mldn.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文件变成了若干个模块文件,这样在启动的时候可以根据程序加载指定的模块(模块中有包),就可以实现启动加快的效果
系统常用包
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是轻量级组件
访问控制权限
在面向对象的开发过程之中有三大主要特点:封装,继承,多态。那么对于封装性而言主要的实现依靠的就是访问控制权限,而访问控制权限在程序之中一共定义有四种:private,default(不写),protected,public
NO | 访问范围 | private | default | protected | public |
---|---|---|---|---|---|
1 | 同一包中的同一类 | √ | √ | √ | √ |
2 | 同一包中的不同类 | × | √ | √ | √ |
3 | 不同包的子类 | × | × | √ | √ |
4 | 不同包的所有类 | × | × | × | √ |
在整个访问控制权限的处理之中,只有protected(受保护)的权限是比较新的概念,下面对这一访问权限的使用进行说明,本次要定义两个类:
- cn.mldn.a.Message类:提供有protect访问权限
- cn.mldn.b.NetMessage类:将直接访问protect属性
范例:定义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.print(super.info); } }
范例:编写测试类,通过子类实现操作
package cn.mldn.test; import cn.mldn.a.*; public class TestMessage{ public static void main(String args[]){ new NetMessage().print(); } }
此时的程序是通过子类访问了父类中的protected属性。但是如果说自此你直接通过Message访问info属性,那么就将出现错误的提示
package cn.mldn.test; import cn.mldn.a.* ; import cn.mldn.a.Message; public class TestMessage { public static void main(String[] args) { System.out.println(new Message().info); } }
在程序之中的封装一共有三个对应的封装权限:private ,default,protect,但是如果每次在使用的时候进行区分会比较麻烦,所有可以给出一个参考的选择方案(90%设计问题):
- 只要是进行属性的定义,全部使用private
- 只要是进行方法的定义,全部使用public