java面向对象方面的知识是难点也是重点,有很多地方去和C++不同。
java中基本类型之外的所有变量类型都是引用类型,如对象和之前学习过的数组。
引用类型变量使用栈空间来存储引用句柄,使用new来申请堆空间。对空间里的值都会被初始化。而一般的栈空间变量,如一个普通的局部变量就不会被初始化。
下面是一段常见的代码:
首先,上面定义了一个Person类,里面同名Person函数 是 Person类的构造函数。
我想说 Person p = new Person("zhangfeng",24); 这段代码创建了一个名字叫"zhangfeng"年龄是24的一个Person对象。
真正的过程应该是, 我 用new 为 Person对象在堆中分配了一个空间,并对其进行值的初始化,一般用‘0’来初始化。
然后,再调用构造函数, 在执行构造函数内部的初始化代码之前。首先会执行类里成员变量初始化自身的代码,如果有的话,
如: public String name = "aaa"; 然后再执行构造函数内的代码。然后再把这个类所在堆空间的首地址赋值给p这个对象引用变量。
这就是一个对象被创建,成员变量被初始化的整个过程。
而所有使用new所申请的空间,最终都会被java的来垃圾回收器回收。(不像c++一定要自己回收,忘了的话就会发生内存泄露。就这点来说java很安全。)
什么时候,对象会变成垃圾呢?
如果指向对象空间的引用变量为null,或者超出了它的生命周期,如:
{
Person p1 = new Person();
}
过了这个代码块,或者p1=null,并且对象对应的堆空间只有p1这个句柄的话,那么此时这个对象就会被当成垃圾。
不过不是变成垃圾,就会立即被垃圾处理器回收。 java的垃圾处理器不可靠,什么时候被回收,这是个不确定的事,也许程序结束了,垃圾也还没被回收掉。 不过当进行垃圾回收时,程序就会自动执行 finalize函数,每个对象都有,继承自Object类。 它类似的C++的
析构函数。 finalize函数什么时候被调用,自然也是不可靠的。
如果你想立即执行垃圾回收, 可以调用 System.gc()。(做为一名c++程序员,不需要主动去清理资源还真不习惯).
关于static成员变量和方法:(理解并活用还是有一定难度的)
static变量,和c++一样,被类的所有对象所共享,可通过类名来直接调用,可用来统计类实例化对象的个数。不过加上private,就不能通过类名来调用了。
在方法前面加上static,就变成了静态方法,也可用类名直接访问。如常见的:
System.out.println();
System.gc();
System其实就是一个类名,out就是System里的一个静态对象变量,而gc()就是一个静态方法了。
一个静态方法,里面不能出现非静态成员变量和方法。原因很容易理解,非静态方法和变量,只有在类的实例化对象中才存在。 但一个静态方法,在未定义对象的时候就可以就被使用。 不过 静态变量和方法都可以出现的非静态方法中。
除了静态变量和方法外,java还支持 静态代码块,如
static
{
count = 2;
System.out.println("static block runs");
}
里面的变量就是静态变量,里面的代码也只会执行一次。只要一个类被使用的时候,这段代码就会被加载执行,如通过类名调用一个静态方法时。
到这里,我们经常用到的代码:
public static void main(String [] args) {}
就容易理解了。
使用public,因为main函数需要在外面被虚拟机调用。
static,因为虚拟机在没有创建对象的情况下就要调用。
void因为main没有返回值。
main的参数String [] args, 这个数组则记录着 解释运行java类时,命令行后面所带的参数,如:
命令 java Person , 此时数组长度为0,因为没有参数, 使用args[0]来访问,就会发生越界。
java Person aa , 此时数组长度为1, args[0]值是aa.
这点和 c/c++有点不同,c/c++中的命令行参数数组, args[0]总是存在的,值是参数前的命令行字符串。从args[1]开始才是对应的命令行参数。
关于static,还有一个非常常用的应用,那就是单例设计模式。对,就是用static来实现。它使得一个类只能实例化一个对象。
理一下思路,只能创建一个对象,那就是说我门不能使用new来创建对象,否则就可以创建多个了。那就要通过构造函数来控制了,将构造函数定义为private的,那么我门就不能在外部调用构造函数。 那么我门该怎么创建这个唯一的对象呢。 看下面的一段代码:
我门在内部加了这句代码: static Single s = new Single();,它会在我门使用这个类的时候执行,这样就创建了一个对象。
外部怎么获得这个对象呢?
我门定义了一个getInstance()来返回对象的引用句柄。必须是static的,我门要在没有创建对象的情况下调用它。由于static函数
只能访问静态成员变量,所以之前的 s变量必须是static的。并且如果不是static的话,Single s = new Single();这条语句还回死
循环式的执行。定义为static,它就只会执行一次了。 到此,我门就创建了一个只能实例化一个对象的类了。单例设计模式,和其他设计模式一样,都是前人的思想结晶。具体它的应用,以后再说,这里只是练习以下static关键字的用法。
内部类:
就是在类内直接定义的类。内部类的成员函数可以访问外部类的成员,但反之外部类不可以访问内部类。 不过外部类,可以用内部类来定义对象后,再访问内部类。(不过给内部类加上static,内部类就相当于是一个外部类一样,不能再访问外部类的成员变量了,类似于静态方法) 看代码:
addSize()表现出了,当外部类和内部类以及内部类成员函数的参数,都存在同一变量的时候,如何区分它们。
内部类的定义,还可以出现在一个程序块中,如一个方法内或for循环内。
不过这个时候内部类要访问代码块中的一个局部变量的时候,这个局部变量必须是final的(final是java中定义常量的方法,类似c++中的
const),否则访问不了。
为什么要定义内部类? 如果我门把一个内部类拿到外面去,但是这个内部类的方法里必须要访问外部类的成员变量。 象在内部类里可以直接访问,但拿到外面,可能内部类的方法,必须加上一个参数,接收外部类的一个对象,通过这个对象再来访问这个对象的成员变量。 这样是不是很麻烦?所以内部类,作为外部类的一部分,不仅仅使一个类的代码更有结构,更清晰,使用起来也给我门带来了许多便利。
java文档工具(javadoc,在jdk的bin目录里面,sun公司提供的文档生成工具,可以生成与官方格式一样的文档)
只要在原码中加入特定格式的注释,就可以了,如:
从上面代码可以知道,文档注释以/**开头,以*/结尾,必须紧挨着被注释的类或方法。 针对不同的注释对象,以‘@’开头的参数,每一个都有特殊的功能,使生成的文档更加详细。具体javadoc使用方法,以后再慢慢研究。
今天就到这了。