11构造函数的定义与作用
特征:与类同名;不含返回值;不用return返回值
注意:在构造方法里不含返回值的概念是不同于“void”的,在定义构造方法时加了“void”,结果这个方法就不再被自动调用了。
作用:当一个类的实例对象刚产生时,这个类的构造方法就会被自动调用,我们可以在这个方法中加入要完成初始化工作的代码。
重载:和一般的方法重载一样,重载的构造方法具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用new 关键字产生对象时,该调用哪个构造方法了。产生对象的格式是:new 类名(参数列表) ;
重载构造方法可以完成不同初始化的操作, 如:p3=new Person(“Tom”,18);语句,会做这样几件事:创建指定类的新实例对象,在堆内存中为实例对象分配内存空间,并调用指定类的构造方法,最后将实例对象的首地址赋值给引用变量p3。
12 p3=new Person(“Tom”,18) 的内存状态变化过程分析
先在内存中创建一个Person对象,调用类的name、age成员变量将对象初始化,然后将Tom放进name中,18放进age中,最后再将这个类对象在堆内存的首地址传给变量p1;
13构造方法的一些细节
在java每个类里都至少有一个构造方法,如果程序员没有在一个类里定义构造方法,系统会自动为这个类产生一个默认的构造方法,这个默认构造方法没有参数,在其方法体中也没有任何代码,即什么也不做。
由于系统提供的默认构造方法往往不能满足编程者的需求,我们可以自己定义类的构造方法,来满足我们的需要,一旦编程者为该类定义了构造方法,系统就不再提供默认的构造方法了。
声明构造方法,如无特殊需要,应使用public关键字,在我们前面例子中,可以使用private访问修饰符,但外部变量就无法访问了,只能通过调用类的公有函数间接访问了
14 this
如果func2方法被调用 ,一定是事先已经有了一个存在的对象,func2被作为那个对象的方法被使用。
在func2内部能引用别的对象 ,同样也能引用func2所属的那个对象。
在func2中,自己所属的那个对象的引用名称是什么呢? this关键字在java程序里的作用和它的词义很接近,它在函数内部就是这个函数所属的对象的引用变量。
14.1 this引用句柄的存放位置
每个成员方法内部,都有一个this引用变量,指向调用这个方法的对象,可以多个this变量指向一个对象;
14.2 this引用句柄的应用
一个类中的成员方法可以直接调用同类中的其他成员,其实我们在一个方法内部使用“this.其他成员”的引用方式和直接使用“其他成员”的效果是一样的,在有些情况下,我们还是非得用this关键字不可的 :
通过this让类的成员变量名和对其进行赋值的成员方法的形参变量同名,方便别人和自己日后阅读理解程序,节省时间。
假设我们有一个容器类和一个部件类,在容器类的某个方法中要创建部件类的实例对象,而部件类的构造方法要接收一个代表其所在容器的参数。
构造方法是在产生对象时被java系统自动调用的,我们不能在程序中象调用其他方法一样去调用构造方法。
但我们可以在一个构造方法里调用其他重载的构造方法,不是用构造方法名,而是用this(参数列表)的形式,根据其中的参数列表,选择相应的构造方法。
15垃圾回收过程分析
java中的finalize()方法:每个java类方法中都有,类似C++的析构函数,由系统提供,但有别于C++,用户不能调用。
20static静态方法
20.1在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。
20.2静态方法不能以任何方式引用this和super关键字(super关键字在下一章讲解)。与上面的理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。
20.3main() 方法是静态的,因此JVM在执行main方法时不创建main方法所在的类的实例对象,因而在main()方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在以后的例子中会多次碰到。
21静态代码块
一个类中可以使用不包含在任何方法体中的静态代码块(static block ),当类被载入时,静态代码块被执行,且只被执行一次,静态块经常用来进行类属性的初始化。
类中的静态代码块被自动执行,无论多少个实例对象,其静态代码块都只被执行一次。程序中用到了其他的类,在第一次使用的时候才装载类。
22单态设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就想是经典的棋谱,不同的棋局,我们用不同的棋谱,免得我们自己再去思考和摸索。使用设计模式也许会制约你去创新,不过真正有意义的创新只能出自少数天才,即使你就是那个天才,虽不必因循守旧,但也不可能完全不去了解和借鉴前人的成功经验。
所谓类的单态设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new 操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
23理解main方法的语法
由于java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。
24内部类 —在类中直接定义的内部类
n 嵌套类可以直接访问嵌套它的类的成员,包括private成员,但是嵌套类的成员却不能被嵌套它的类直接访问。
n 在内部类对象保存了一个对外部类对象的引用,当内部类的成员方法中访问某一变量时,如果在该方法和内部类中都没有定义过这个变量,内部类中对this的引用会被传递给那个外部类对象的引用。
n 如果用static修饰一个内部类,这个类就相当于是一个外部定义的类,所以static的内部类中可声明static成员,但是,非static的内部类中的成员是不能声明为static的。static的内部类不能再使用外层封装类的非static的成员变量,这个道理不难想象!所以static嵌套类很少使用。
如果函数的局部变量(函数的形参也是局部变量),内部类的成员变量,外部类的成员变量重名,我们应该按下面的程序代码所使用的方式来明确指定我们真正要访问的变量。
public class Outer
{
private int size;
public class Inner
{
private int size;
public void doStuff( int size)
{
size++; // 引用的是doStuff函数的形参
this.size++; //引用的是Inner类中的成员变量
Outer.this.size++; // 引用的Outer类中的成员变量
}
}
}
内部类被外部引用Outer.Inner inner = outer.new Inner();
内部类 —在方法中定义的内部类
n 嵌套类并非只能在类里定义,也可以在几个程序块的范围之内定义内部类。例如,在方法中,或甚至在for循环体内部,都可以定义嵌套类 。
n 在方法中定义的内部类只能访问方法中的final类型的局部变量,用final定义的局部变量相当于是一个常量,它的生命周期超出方法运行的生命周期。
25使用Java的文档注释
n 文档注释以“/**”开始,以“*/”标志结束,相应的信息和批注所对应的位置很重要! 类的说明应在类定义之前,方法的说明应在方法的定义之前。
n 批注参数来标记一些特殊的属性及其相应的说明 。
– @author<作者姓名> //固定格式,不能写错 @自动带有换行
– @version<版本信息>
– @param<参数名称><参数说明>
– @return<返回值说明>
备份今天试验代码1:
/*PassParam类实现字符串输入数据测试,参数传递问题;*/
/*通过TestChinese类对Chinese类中方法的访问来理解static方法;*/
class PassParam
{
int x;
public static void main(String [] args) //main不要创建对象,所以是静态的;String运行时装入,参数用空格隔开
{
System.out.println(args[0]); //使用java PassParam aaa,将aaa存放到数组中,就能打印出来了;参数一空格隔开;
System.out.println(args[1]);
/*int x = 5;
change(x);
System.out.println(x);*/ //输出结果仍为5,未变;
PassParam obj = new PassParam();
obj.x = 5;
change(obj); //如果change不是静态的,需要先创建对象;
System.out.println(obj.x); //引用数据类型参数传递,改变了引用变量指向的内存对象内容,输出结果变为3,
int []x = new int[1];
x[0] = 5;
change(x);
System.out.println(x[0]);
}
/*public static void change(int x)
{
x = 3;
} */
public static void change(PassParam obj)
{
obj = new PassParam(); //引用变量指向了新地址,而非原main方法中obj所指地址,所以使main中输出结果为5;
obj.x = 3;
}
public static void change(int [] x)
{
x[0] = 3;
}
}
class Chinese
{
static Chinese objRef = new Chinese();//static 不会让创建对象分配内存的情况循环下去;只创建一个实例对象;
private static int count = 0; //如果不是static时候,就是各自对立的,不是共享的
private static String country = "zhongguo";
static
{
count = 2;
System.out.println("static code");
}
String name;
int age;
public static Chinese getInstance() //私有后外面不能创建对象,但可以自己创建对象,提供外面使用;
{
return objRef;
}
private Chinese()
{
//count++;
System.out.println(++count);
}
static void sing()
{
System.out.println("啊!");
//singOutCountry();
}
void singOurCountry()
{
System.out.println(country);//out是类System中静态的成员变量,调用其指向的对象println;
sing(); //非静态方法能去访问静态方法,但不能去访问非静态方法,因为非静态方法只有创建了对象后才真正存在;
}
}
class TestChinese
{
public static void main(String [] args)
{
/*System.out.println(Chinese.country);
Chinese ch1 = new Chinese();
ch1.singOurCountry();
System.out.println(ch1.country);*/
/*System.out.println("begin");
Chinese.sing(); //静态代码块在此期间执行,
System.out.println("end");
new Chinese().sing();
new Chinese().singOurCountry();
new Chinese();*/
Chinese obj1 = Chinese.getInstance();
Chinese obj2 = Chinese.getInstance();
System.out.println(obj1 == obj2);// 引用的是同一个实例对象;
}
}
备份今天试验代码2:
/*内部类的创建及其作用理解;*/
class Outer
{
int outer_i = 100;
void test()
{
//int x = 0; //类中定义中的变量,编译器会自动为其初始化,但方法中定义的变量需要先定义;final相当于常量,使其生命周期超过方法的运行期间;
Inner in = new Inner(/*this*/);
in.display();
}
public static void main(String [] args)
{
Outer outer = new Outer();
outer.test();
}
class Inner //用static修饰的话,相当于在外部定义的类;也可以在方法中;final 变量名后才能访问方法中的变量
{
/*Outer outer;
public Inner(Outer outer)
{
this.outer = outer;
}*/ //加上以上代码才能在外部访问Outer的 成员变量;
//int inner_i = 50;
void display()
{
System.out.println("outer_i = "+ outer_i);//成功调用外部类的变量;
}
}
}