为了解决类名重复产生冲突的问题以及更好地组织类,Java提供了包机制,用于区别类名的命名空间,便于软件版本的发布。包里通常存放的是类文件,因为编写程序的时候,难免会有类名相同的情况。为了对类进行分类管理,java提出了包机制解决方案,在不同包中可以有相同的类名,调用的时候连同包名一起就行。
包的作用1、将功能相近的类放在同一个包中,可以方便查找与使用。
2、避免多个类重名的情况,如果出现两个相同名字的类,可通过包将两者区分,从而避免冲突。
3、包的出现可以将java的类文件和源文件相分离。
Java使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。在调用其他包中的类时,需要写类的全称,也就是连同包名一起书写。当类存在多层包中时,使用import导入后,使用其类时,就可以不加包名了。一个程序文件中只有一个package,可以有多个import。import导入的是包中的类或静态成员。
包的定义语句必须写在类文件的第一行,并且包名为全小写字母组成。因为要先有包,才知道class文件的存放位置。
带有包名的类的全称格式为:包名.类名。
编译定义了包的程序文件时,在编译时要指定包的存储目录。
如:javac–dD:\CLASSPATH类名.java
下面是JDKArrayList的源代码,可以看到这个类位于java.util包中,而且它还用import语法引入了3个其他包中的类。
使用包中的类1、使用类的全限定名
使用全限定名引用包中的类比较简单,只需要在每个类名前面加上完整的包名即可。例如,创建ArrayList类的对象并实例化该对象的代码如下:
ArrayListal=newArrayList();
2、使用import语句引入包中的类
由于使用全限定名引用包中的类的方法比较繁琐,所以Java提供了import语句来引入包中的类。import语句的基本语法格式如下:
import包名1[.包名2.……].类名
*;
当存在多个包名时,各个包名之间使用“.”分隔,同时包名与类名之间也使用“.”分隔。*:表示包中所有的类。
访问修饰符访问修饰符是用来控制类、属性、方法的可见性的关键字称之为访问修饰符。
1、private访问控制符
如果一个成员方法或成员变量名前使用了private访问控制符,那么这个成员只能在这个类的内部使用。
注意:不能在局部变量前加private修饰符。
2、默认访问控制符
如果一个成员方法或成员变量名前没有使用任何访问控制符,就称这个成员所拥有的是默认的(default)访问控制符。默认的访问控制成员可以被这个包中的其它类访问。如果一个子类与其父类位于不同的包中,子类也不能访问父类中的默认访问控制成员。
3、protected访问控制符
如果一个成员方法或成员变量名前使用了protected访问控制符,那么这个成员既可以被同一个包中的其它类访问,也可以被不同包中的子类访问。
4、public访问控制符
如果一个成员方法或成员变量名前使用了public访问控制符,那么这个成员可以被所有的类访问,不管访问类与被访问类是否在同一个包中
Jar包jar文件是一种打包文件javaactiveFile,与zip兼容,称之为jar包。当我们开发了很多类,需要将类提供给别人使用,通常以jar包形式提供.当项目写完之后,需要及将class字节码文件打包部署给客户。将class文件打包发布,可以使用jar命令.
jar命令1、jar工具存放于jdk的bin目录中(jar.exe);
2、jar工具:主要用于对class文件进行打包(压缩);
3、dos中输入jar查看帮助。
创建jar包
jar-cvfmypackage.jarfileafileb
查看jar包
jar-tvfmypackage.jar[定向文件]
解压缩
jar-xvfmypackage.jar
自定义jar包的清单文件
jar–cvfmmypackage.jarmf.txtfileafileb
模版方法设计模式模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法设计模式。
比如定义一个操作中的算法的骨架,将一些步骤延迟到子类中。模板方法使得子类能够不去改变一个算法的结构即可重定义算法的某些特定步骤。
模版模式中的角色
1、抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。
2、具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。
下面示例演示下熊出没中各主角一天的生活情况。简单描述一下:熊出没中有伐木工、老板、狗熊等类,程序使用模版方法模式,记录所有“人员”一天的情况:
首先来个超类,超类中定义了一个workOneDay方法,设置为作为算法的骨架:
/***
authorKenWang*create-12-:35*/publicabstractclassWorker{protectedStringname;publicWorker(Stringname){this.name=name;}/**记录一天的工作*/publicfinalvoidworkOneDay(){System.out.println("-----------------workstart---------------");enterForest();work();exitForest();System.out.println("-----------------workend---------------");}/**工作*/publicabstractvoidwork();/**进入森林*/publicvoidenterForest(){System.out.println(name+"进入森林");}/**离开森林*/publicvoidexitForest(){System.out.println(name+"离开森林");}}上面程序定义了一个每天工作(算法)的骨架,包含以下步骤:
a、进入森林
b、工作情况
c、离开森林
可以看到,a、c我们在超类中已经实现(分别输出一句话),子类仅需实现work这个抽象方法,记录每天的工作情况。下面各个角色登场:
伐木工:
/***
authorKenWang*create-12-:02*/publicclassTimberjackextendsWorker{publicTimberjack(Stringname){super(name);}Overridepublicvoidwork(){System.out.println(name+"打开锯子疯狂砍树");}}李老板:
/***
authorKenWang*create-12-:04*/publicclassBossextendsWorker{publicBoss(Stringname){super(name);}Overridepublicvoidwork(){System.out.println(name+"弄张报纸听着小曲");}}狗熊:
/***
authorKenWang*create-12-:06*/publicclassBearextendsWorker{publicBear(Stringname){super(name);}Overridepublicvoidwork(){System.out.println(name+"抱着蜂蜜追光头强");}}客户端测试程序:
/***
authorKenWang*create-12-:12*/publicclassClient{publicstaticvoidmain(String[]args){Timberjacktbj=newTimberjack("光头强");tbj.workOneDay();Bossboss=newBoss("李老板");boss.workOneDay();Bearbear=newBear("熊二");bear.workOneDay();}}运行客户端程序,输出结果如下:
至此,大家应该已经理解模版方法设计模式的原理和作用了。
模版方法方式里面也可以设置钩子函数,比如现在希望记录伐木工离开森林(狗熊岭)的时间,我们就可以在超类中添加一个钩子函数(isNeedPrintTime):
/***
authorKenWang*create-12-:35*/publicabstractclassWorker{protectedStringname;publicWorker(Stringname){this.name=name;}/**记录一天的工作*/publicfinalvoidworkOneDay(){System.out.println("-----------------workstart---------------");enterForest();work();exitForest();System.out.println("-----------------workend---------------");}/**工作*/publicabstractvoidwork();/**进入森林*/publicvoidenterForest(){System.out.println(name+"进入森林");}/**离开森林*/publicvoidexitForest(){if(isNeedPrintTime()){System.out.print(LocalDateTime.now().withNano(0)+"--");}System.out.println(name+"离开森林");}publicbooleanisNeedPrintTime(){returnfalse;}}超类中添加了一个isNeedPrintDate方法,且默认返回false,不打印时间。如果某子类需要调用打印时间,可以重写这个钩子方法,返回true即可,比如,伐木工重写了这个方法:
***
authorKenWang*create-12-:02*/publicclassTimberjackextendsWorker{publicTimberjack(Stringname){super(name);}Overridepublicvoidwork(){System.out.println(name+"打开锯子疯狂砍树");}OverridepublicbooleanisNeedPrintTime(){returntrue;}}客户端调用程序不变,最终程序输出结果如下:
可以看到光头强在离开森林的时候,打印了时间。关于程序中的钩子(函数),超类中可提供默认实现或者空实现,子类可覆盖或者不覆盖,具体根据业务需求来定。
数组去重题外篇:写一个程序去除数组中的重复元素,并返回去重后的新数组。
/***
authorKenWang*create-12-:25*/publicclassDemo{publicstaticvoidmain(String[]args){int[]arr=newint[]{11,2,9,11,2,10,11,20};System.out.println("去重之前数组为:"+Arrays.toString(arr));System.out.println("去重之后数组为:"+Arrays.toString(removeRepeat(arr)));}//去除数组中的重复元素,并返回新数组publicstaticint[]removeRepeat(int[]arr){intcount=0;//重复元素的个数//计算重复元素的个数for(inti=0;iarr.length-1;i++){for(intj=i+1;jarr.length;j++){if(arr[i]==arr[j]){count++;break;}}}//新数组的长度=元数组长度-重复元素个数intnewArrLength=arr.length-count;//新数组int[]newArr=newint[newArrLength];//新数组的索引intindex=0;//将原数组中的元素加入新数组for(inti=0;iarr.length;i++){//标记是否已在新数组中添加过booleanflag=false;for(intj=0;jnewArr.length;j++){if(arr[i]==newArr[j]){//已在新数组中添加过flag=true;break;}}if(flag==false){//未在新数组中添加过newArr[index++]=arr[i];}}returnnewArr;}}这个程序不属于本篇讨论的范畴,只是在这里写出来让大家再去复习一下数组,因为数组这一数据结构在以后的开发中会频繁使用,另外提醒大家去阅读一下java.util.Arrays这个类的源代码。