1、帮助文档的制作javadoc
1.1、先举一个例子来说明
首先我们定义一个工具类“ArrayTool”,并将这个类放在“G:\java\lkj”目录之下,然后我们在“G:\java1”目录之下创建一个“Demo”类来调用“ArrayTool”,如下图:
public class Demo {
public static void main(String[] args) {
int[] arr = {3,4,5,6};
int max = ArrayTool.getMax(arr);/
System.out.println(max);
}
}
出现如下图所示的错误
由于我们调用的“ArrayTool.java”类并不在当前目录之下,因此找不到这个类,那么我们设置路径将这个类的路径“G:\java\lkj”添加到我们的系统环境变量中,以便虚拟机可以找到该类,如下图
显示无法加载主类,这个时候在当前路径“G:\java1”之下明明就有“Demo.class”类,为什么还运行不了?
因为我们之前将路径设置为“G:\java\lkj”,没有在路径后面加上“;”符号,因此虚拟机在这个路径下找到“ArrayTool.class”之后,并不会回到当前目录之下找“Demo.class”类加载,因此我们必须将路径设置为“G:\java\lkj;”,加上“;”表示在设置的路径查找不到再回到当前路径下查找,或者是设置为“.;G:\java\lkj”,表示先在当前路径下查找,找不到再到我们设置的路径下面查找。最好设置为后面一种。2类结果如下所示:
上面的实验也说明,我们如果要使用某一个功能,与其相关的类必须全部放在同一个文件夹之下(如下图),不然就得将所需类的“.class”文件的路径添加到环境变量中,这样程序才能运行。
另一方面,如果我们获得的某个类的“.java”文件,还要在其路径下对其编译,并将其编译后获得的“.class”文件的路径添加到环境变量中才可以运行,并回到我们主函数所在类的路径之下,编译并运行主函数,这样才不会出错。如我们在路径“G:\java1”下放主函数类“Demo.java”,在路径“G:\java”下放工具类“ArrayTool.java”,按上面的步骤,如下图
G:\>cd java
//进入java文件夹编译ArrayTool.java
G:\java> javac ArrayTool.java
//将ArrayTool.class的位置添加到环境变量
G:\java>set classpath=.;G:\java
G:\java>cd\
G:\>cd javal
//进入java1文件夹,编译Demo.java文件
G:\java1>javac Demo.java
G:\java1>java Demo
//成功运行
6
但是,就算把“ArrayTool.class”给你,你将其路径添加到环境变量中并加载,由于你不知道这个类的具体功能,你也没办法使用它,差个说明书!
1.2、帮助文档的制作
java的说明书通过文档注释来完成,以后,我们每编写一个功能都必须使用文档注释对其进行说明注释。如下,我们对ArrayTool工具类进行文档注释。我们编辑一个包含下面代码的ArrayTool类。
首先,我们输入下面语句
javadoc -d myhelp -anthor -version ArrayTool.java
//其中,“-d”表示生成目录的位置,如果我们所写的文件夹不存在,系统会帮助我们创建,后面跟着作者、版本信息,最后是要创建帮助文档的“ArrayTool.java”文件。
报错!!一个类如果想生成帮助文档,这个类必须是public类型(或者说protected类型)。
我们修改错误后,帮助文档自动生成
我们只需要看index.html文件即可。文档想要体现的,是我们准备对外暴露的内容,只能生成用public与protected修饰的内容。
一个类中默认会有一个空参数的构造函数,这个默认的构造函数的权限和所属类一致。如果类被public修饰,那么默认的构造函数也带public修饰符。如果类没有被public修饰,那么默认的构造函数,也没有public修饰。总而言之,默认构造构造函数的权限是随着的类的变化而变化的。
需要注意的是,我们自己写一个空参数的构造函数,不是默认构造函数,我们不写构造函数,那么空参数函数就是构造函数,其修饰符就随类而变化。如下面代码,我们写了 ArrayTool() {},但是这个只是空参数的构造函数,并不是默认构造函数,因此其不随ArrayTool类是public类型,相应生成帮助文档,必须将其设置为public类型
/**
首先,是对类的描述:这是一个可以对数组进行操作的工具类,该类中提供了,获取最值,排序等功能。
使用文档注释中特殊的表示,他们可以被文档注释工具所提取并识别
@author lkj
@version V1.1
*/
public class ArrayTool{//工具类
/**
将空参数的构造函数私有化,防止其他类创建本类对象
*/
private ArrayTool() {}
// 对于每一个功能也必须使用文档注释进行描述 ,凡是public所描述地功能(方法)都可以用文档注释进行描述,因为他们都可以被文档注释工具所提取
/**
对功能的描述:获取一个整形数组中的最大值
@param arr 接受一个int类型的数组
@return 返回所传进数组的最大值
*/
public static int getMax(int[] arr) {
int max = 0;
for(int x=1; x<arr.length ;x++) {
if(arr[x]>arr[max])
max = x;
}
return arr[max];
}
/**
对功能的描述:获取一个整形数组中的最小值
@param arr 接受一个int类型的数组
@return 返回所传进数组的最小值
*/
public static int getMin(int[] arr) {
int min = 0;
for(int x=1; x<arr.length ;x++) {
if(arr[x]<arr[min])
min = x;
}
return arr[min];
}
/**
对一个int型数组进行冒泡排序
@param arr 接受一个int类型的数组
@return 返回排序完成的数组
*/
public static int[] bubbleSort(int[] arr) {
for(int i=1; i<arr.length ;i++) {
for(int j=0; j<arr.length-i ;j++) {
if(arr[j]>arr[j+1])
swap(arr[j],arr[j+1]);
}
}
return arr;
}
/**
对两个数进行位置置换
@param num1 要置换的第一个数
@param num2 要置换的第二个数
*/
private static void swap(int num1,int num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
}
这里我们所描述的,就是程序的说明文档,也就是帮助文档(API,application program interface:应用程序接口)。接口就是对外暴露东西,也就是将你的程序中需要给其他人看的部分暴露给其他人使用,并对你的暴露出来的内容进行使用说明。
如何在eclipse中生成帮助文档 添加链接描述
需要注意,eclipse中一个java文档(就是一个界面中)只能有一个public类型的类,否则会报错!如果所创建的类都是public类型。则需要创建多个java文档。
2、静态代码块
2.1、静态代码块的介绍与说明
如果在执行类时,希望先执行类的初始化动作,可以使用static定义一个静态区域。静态代码块随着类的加载而执行,并且只会执行一次。静态代码块优先于主函数执行。
public class AnyThting {
static {
//程序块
}
}
看如下代码:
class StaticCode{
static
{
System.out.println("a");
}
}
class StaticCodeDemo {
//静态代码块初始化类
static
{
System.out.println("b");
}
public static void main(String[] args) {
//StaticCodeDemo包含主函数,它是程序的入口,其会先进内存
//因此先执行StaticCodeDemo类的静态代码块,对这个类进行初始化
//随后创建StaticCode类对象进行,这个类进入内存,其静态代码块执行
new StaticCode();
new StaticCode();//又一次创建对象,类已经初始化在内存中了,再次创建对象并不会再次执行静态代码块
System.out.println("over");
}
static
{
System.out.println("c");
}
}
结果如下:
b
c
a
over
** 如果我们不创建类的对象,仅仅是使用类名调用方法,但是只要类有加载到栈内存中**,其静态代码块依然会被加载,如下代码
class StaticCode{
static
{
System.out.println("a");
}
public static void show() {
System.out.println("show run");
}
}
class StaticCodeDemo {
public static void main(String[] args) {
//没有创建StaticCode类的对象,但是这个类要加载,依然会执行静态代码块
StaticCode.show();
}
}
结果如下:
a
show run
再看如下代码:
class StaticCode{
static
{
System.out.println("a");
}
}
class StaticCodeDemo {
public static void main(String[] args) {
//创建StaticCode类的变量,但是该变量不指向任何东西,因此该类不加载进内存
StaticCode s = null;
}
}
//结果为不显示a
总结:只有类中有内容被使用,这个类才会加载进内存,才会执行静态代码块!
2.2、静态代码块与构造代码块的对比(见黑马视频6.7)
构造代码块作用:给对象进行初始化。对象一建立就运行,而且优先于构造函数执行。
和静态函数的区别:静态代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化。 基于静态代码块可以给所有对象统一初始化,它可以用来定义对象共性内容。
{
//构造代码块
}
区别:
(1)静态代码块是对类初始化,只在类加载的时候执行一次;构造代码块是对对象进行初始化,每创建一个对象,构造代码块就会执行!
class StaticCode{
//无参数的构造函数
StaticCode()
{
System.out.println("b");
}
//静态代码块
static
{
System.out.println("a");
}
//构造代码块
{
System.out.println("c");
}
//一个int类型参数的构造函数
StaticCode(int x)
{
System.out.println("d");
}
}
class StaticCodeDemo {
public static void main(String[] args) {
//先执行类的加载,执行静态代码块,给类初始化
//接下来创建对象,执行构造代码块,给所有对象初始化
//接下来执行构造函数,给对应对象初始化
new StaticCode(4);
}
}
//结果是:a c d
再注意静态成员与非静态成员的访问方式!创建对象时代码执行的优先级:静态代码块>构造代码块>构造函数
3、对象的初始化过程
先看如下代码
class Person
{
private String name = "haha";
private int age;
private static String country = "cn";
//构造函数
Person(String name,int age)
{
this.name = name;
this.age = age;
System.out.println(this.name+"..."+this.age);
}
//构造代码块
{
System.out.println(this.name+"..."+this.age);
}
}
public class Demo1 {
public static void main(String[] args) {
Person p = new Person("lkj",20);
}
}
//结果是
haha...0//构造代码块先于构造函数执行,而虚拟机对成员变量隐式赋值赋值先于构造函数赋值
lkj...20
创建对象过程总结:Person p = new Person(“lkj”,20);
1)因为new用到了Person.class类,所以会先找到Person.class文件并加载到内存中。
2)执行该类中的static代码块,如果有的话,给person.class类进行初始化。
3)在堆内存中开辟空间,分配内存地址。
4)在堆内存中建立对象的特有属性,并进行默认初始化。
5)对属性进行显式初始化(如果有的话)。
6)对对象进行构造代码块初始化。
7)对对象进行对应的构造函数初始化。
8)将内存地址赋值给栈内存中的p变量。
4、对象调用成员过程(见黑马视频6.8)
注意,静态变量、常量、类相关信息(包括方法的代码)都存储在内存的方法区,而在创建对象的时候,相应的成员变量代码与成员方法的地址值会加载到堆内存中(见就业班-day06视频内存解析)。在加载类的时候,静态的方法与变量会比非静态的方法先加载进方法区内存。
我们在写代码的时候,在同一个类中,非静态的变量与方法部分会省略“this.”,代表本类对象调用,但是因为在同一个类中无需使用对象来调用它,因此可以省略this;而静态部分省略“类名.”,代表类调用,但是因为在同一个类中无需使用类名来调用它,因此可以省略类名。
不管是方法中的局部变量,还是形参中的局部变量,都是在栈内存中创建空间的!
**注意视频内关于内存区域的分析!!!**由于内容较难以描述,以视频的解说为主!不理解的部分放慢多看几遍,内存部分的分析很重要!!!
5、单例设计模式
5.1、方式一
设计模式:解决某一类问题最行之有效的方法。java中23种设计模式。我们今天讲解单例设计模式:解决一个类在内存只存在一个对象。
为什么会有一个类在内存中只创建一个对象的现象,见黑马视频6.8中9分30秒处开始的解释,会有只创建一个对象的情况出现。
如何保证对象唯一?
1)为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象;
2)还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象;
3)为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三步怎么用代码体现呢?
1)将构造函数私有化;
2)在类中创建一个本类对象;
3)提供一个方法可以获取到该对象。
原则:对于事物该怎么描述,还怎么描述。当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
/*
这个是先初始化对象,称为:饿汉式。
特点:Single类一进内存,就已经创建好了对象。
*/
class Single{
//第一步,将构造函数私有化,防止外界创建对象
private Single() {}
//在类中创建一个本类对象
//另一方面,s是类中的成员变量,为了避免外界通过类名直接对其调用,我们将其私有化,这样就只能通过getInstance()方法访问
private static final Single s = new Single();//将s设定为final更加严谨
//提供一个方法可以获取到该对象,该方法外部类不能提供对象,只能通过类名调用,将方法设置为静态
//静态方法只能直接访问静态成员,这里没办法通过对象访问,因此必须将对象s设置为静态
public static Single getInstance() {
return s;
}
}
class SingleDamo {
public static void main(String[] args) {
//获取对象,通过这个方法,无论外界创建多少个对象,都指向内存中的同一个对象
//这样便保证一个类在内存中对象的唯一性
Single s = Single.getInstance();
}
}
那么我们在下面的代码中试验一下
class Single{
private int num;
public void setNum(int num) {
this.num = num;
}
public int getNum() {
return num;
}
}
class SingleDamo {
public static void main(String[] args) {
Single s1 = new Single();
Single s2 = new Single();
s1.setNum(30);
//因为s1与s2是不同的对象,s1改变num的值是针对它这个对象本身,而原来的num值并没有改变
System.out.println(s2.getNum());
}
}
//结果是
0
//说明s1\s2代表不同对象
再看
class Single{
private int num;
public void setNum(int num) {
this.num = num;
}
public int getNum() {
return num;
}
private Single() {}
private static final Single s = new Single();
public static Single getInstance() {
return s;
}
}
class SingleDamo {
public static void main(String[] args) {
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
s1.setNum(30);
System.out.println(s2.getNum());
}
}
//结果是
30
//说明s1\s2代表同一个对象
5.2、方式二
代码如下
/*
对象是方法被调用时才初始化,也叫做对象的延时加载,称为懒汉式。
Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
*/
class Single{
private Single() {}
private static Single s = null; //懒汉式s不能设置为空
public static Single getInstance() {
if(s == null)
s = new Single();
return s;
}
}
class SingleDamo {
public static void main(String[] args) {
Single s = Single.getInstance();
}
}
注意黑马视频6.10,里面讲解的方式1与方式2在内存中的不同操作过程!
懒汉式与饿汉式差不多,开发的时候一般使用饿汉式,既先加载对象。因为饿汉式安全简单,懒汉式容易出现小问题,这种情况见6-10的11分10秒开始处视频。