- 1. 对象的构造方法
- 1.1 构造方法的语法规则
- 1.2 重载构造方法
- 1.3 this语句的语法
- 1.4 默认构造方法
- 1.5 调用父类构造方法super
- 2. 静态工厂方法
- 2.1 静态工厂方法
- 2.2 静态工厂方法的命名约定
- 2.3 静态工厂方法的应用
- 2.3.1 静态工厂方法的应用之一:创建单例类
- 2.3.2 静态工厂方法的应用之一:创建松耦合系统
- 3. 垃圾回收
- 3.1 垃圾回收对程序透明
- 3.2 对象的finalize()方法
构造方法必须满足以下语法规则:
- 方法名必须与类名相同。
- 不要声明返回类型。
- 不能被static、final、abstract修饰。构造方法不能被子类继承(能被调用用super),所以用final和abstract修饰没有意义。构造方法用于初始化一个新建的对象,所以用static修饰没有意义。
当通过new语句创建一个对象时,在不同的条件下,对象可能会有不同的初始化行为。例如对于公司新进来的三个员工(Employee):
员工一:姓名(“无名氏”)和年龄(-1)是未知的
员工二:姓名(Mike)已知,年龄(-1)未知
员工三:姓名(Tom)和年龄(32)都是已知
可通过重载构造方法来表达对象的多种初始化行为。
public class Employee {
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age=age;
}
public Employee(String name) {
this(name, -1);
}
public Employee() {
this( "无名氏" );
}
public void setName(String name){
this.name=name;
}
public String getName(){return name; }
public void setAge(int age){this.age=age;}
public int getAge(){return age;}
}
Employee e1=new Employee();
Employee e2=new Employee(“Mike");
Employee e3=new Employee(“Tom",32);
1.3 this语句的语法
通过构造方法中的this语句调动其他的构造方法
(1)假如在一个构造方法中使用了this语句,那么它必须作为构造方法的第一条语句(不考虑注释语句)。以下构造方法是非法的:
(2)只能用this语句来调用其他构造方法,而不能通过方法名来直接调用构造方法。以下对构造方法的调用方式是非法的:
- 默认构造方法是没有参数的构造方法,可分为两种:
(1)隐含的默认构造方法
(2)程序显式定义的默认构造方法。 - 在Java语言中,每个类至少有一个构造方法。为了保证这一点,如果用户定义的类中没有提供任何构造方法,那么Java语言将自动提供一个隐含的默认构造方法。该构造方法没有参数,用public 修饰,而且方法体为空,格式如下:
public class Sample1{} //有一个隐含的默认构造方法
public class Sample2{ //有参数,没有默认构造方法 因此并不是所有类都有默认构造方法
public Sample2(int a){System.out.println("My Constructor");}
}
public class Sample3{ //有一个显式定义的默认构造方法
public Sample3(){System.out.println("My Default Constructor");}
}
1.5 调用父类构造方法super
在子类的构造方法中,可以通过super语句调用父类的构造方法。
用super语句来调用父类的构造方法时,必须遵守以下语法规则:
(1)假如在子类的构造方法中有super语句,它必须作为构造方法的第一条语句(不考虑注释语句) 因此在一个构造方法中不可能同时出现this语句和super语句
(2)在子类的构造方法中,不能直接通过父类方法名调用父类的构造方法,而是要使用super语句,
(3)当子类的构造方法没有通过super语句调用父类的构造方法,那么Java虚拟机会自动先调用父类的默认构造方法。
创建类的实例的最常见的方式是用new语句调用类的构造方法。在这种情况下,程序可以创建类的任意多个实例,每执行一条new语句,都会导致内存中产生一个新的对象。(任意创建无数对象会占用大量的内存,会影响程序的运行性能,需要加以控制)
假如类需要进一步封装创建自身实例的细节,并且控制自身实例的数目,那么可以提供静态工厂方法。
例如Class实例是Java虚拟机在加载一个类时自动创建的,程序无法用new语句创建java.lang.Class类的实例,因为Class类没有提供public类型的构造方法。
下图所示:java虚拟机在加载Sample类时自动创建Sample类的class对象,程序是无法创建实例
为了使程序能获得代表某个类的Class实例,在Class类中提供了静态工厂方法forName(String name),它的使用方式如下:
Class c=Class.forName(“Sample”); //返回代表Sample类的实例
下面举一个例子来说明,
Gender类的静态工厂方法:
public class Gender{
private String description;
private static final Gender female=new Gender("女");
private static final Gender male=new Gender("男");
private Gender(String description){this.description=description;} //private私有化
public static Gender getFemale(){ //静态工厂方法
return female;
}
public static Gender getMale(){ //静态工厂方法
return male;
}
public String getDescription(){return description;}
}
外部程序无法创建Gender实例,当运行上面程序时,内存中就只有两个Gender实例(female和male),外部通过getXXXX方法获得这两个实例;
2.2 静态工厂方法的命名约定语法层面并没有强行规定,是编程者的约定俗成,增加可阅读性和理解性;
静态工厂方法命名为valueOf或者getInstance:
1)valueOf:该方法返回的实例与它的参数具有同样的值。例如:
Integer a=Integer.valueOf(100); //返回取值为100的Integer对象
从上面代码可以看出,valueOf()方法能执行类型转换操作,在本例中,把int类型的基本数据转换为Integer对象。
2)getInstance:返回的实例与参数匹配,例如:
//返回符合中国标准的日历对象
Calendar cal=Calendar.getInstance(Locale.CHINA);
单例类是指仅有一个实例的类。在系统中具有惟一性的组件可作为单例类,这种类的实例通常会占用较多的内存,或者实例的初始化过程比较冗长,因此随意创建这些类的实例会影响系统的性能。
public class GlobalConfig {
private static final GlobalConfig INSTANCE=new GlobalConfig(); //GlobalConfig 类的唯一实例
private Properties properties = new Properies();
private GlobalConfig(){ //private私有化
try{
//加载配置信息
InputStream in=getClass().getResourceAsStream("myapp.properties");
properties.load(in); in.close();
}catch(IOException e){throw new RuntimeException("加载配置信息失败");}
}
public static GlobalConfig getInstance(){ //静态工厂方法,返回唯一的实例
return INSTANCE;
}
public Properties getProperties() { return properties; }
}
2.3.2 静态工厂方法的应用之一:创建松耦合系统
松耦合系统:系统的各个子系统都相互独立,当一个系统发生变化时,不会对其他系统发生很大的影响,系统与系统之间通过接口来相互访问;
一个类的静态工厂方法可以返回子类的实例,这一特性有助于创建松耦合的系统接口,即其他程序可以通过简单的接口访问该系统,无需深入涉及该系统内部的实现细节。
eg:
ServiceFactory.java
public ServiceFactory{
private static final String serviceImpl;
static{ //ServiceFactory的配置信息
//读取配置信息,根据配置信息设置服务实现类的类型,假定为
//ServiceImpl1
serviceImpl="ServiceImpl1";
}
public static ServiceIFC getInstance(){
Class.forName(serviceImpl).newInstance();
}
}
客户层访问服务
当客户层需要获得业务逻辑层的服务时,先从静态工厂类ServiceFactory中获得ServiceIFC接口的实现类的实例,然后通过接口访问服务:
ServiceIFC service=ServiceFactory.getInstance(); //得到某个实例 service.service1(); //不再访问具体实现类3. 垃圾回收
- Java虚拟机提供了一个系统级的垃圾回收器线程,它负责自动回收那些无用对象所占用的内存,这种内存回收的过程被称为垃圾回收(Garbage Collection)。
- 垃圾回收有以下优点:
把程序员从复杂地内存追踪、监测和释放等工作中解放出来,减轻程序员进行内存管理的负担。
防止系统内存被非法释放,从而使系统更加健壮和稳定。 - 垃圾回收具有以下特点:
只有当对象不再被程序中的任何引用变量引用,它的内存才可能被回收。
程序无法迫使垃圾回收器立即执行垃圾回收操作。
当垃圾回收器将要回收无用对象的内存时,先调用该对象的finalize()方法。
- 当一个对象成为无用对象,垃圾回收线程何时执行它的finalize()方法,何时回收它的内存,这对于程序来说都是透明的。程序只能决定一个对象何时不再被任何引用变量引用,使得它成为可以被回收的垃圾。
- 在程序中可以调用System.gc()或者Runtime.gc()方法提示垃圾回收器尽快执行垃圾回收操作,但是这也不能保证调用完该方法后,垃圾回收线程就立即执行回收操作,而且不能保证垃圾回收线程一定会执行这一操作。
- 当垃圾回收器将要释放无用对象的内存时,会先调用该对象的finalize()方法。如果在程序终止之前垃圾回收器始终没有执行垃圾回收操作,那么垃圾回收器将始终不会调用无用对象的finalize()方法。
- 在Java的Object祖先类中提供了protected类型的finalize()方法,因此任何Java类都可以覆盖finalize()方法,在这个方法中进行释放对象所占的相关资源的操作。
- Java虚拟机的垃圾回收操作对程序完全是透明的,因此程序无法预料某个无用对象的finalize()方法何时被调用,以及是否被调用。
- 但由于垃圾回收器是否会执行finalize()方法、以及何时执行该方法,都是不确定的,因此在程序中不能依赖finalize()方法来完成同时具有以下两个特点的释放资源的操作:
1)必须执行。
2)必须在某个确定的时刻执行。 - 在多数情况下,应该避免使用finalize()方法,因为它会导致程序运行结果的不确定性。在某些情况下,finalize()方法可用来充当第二层安全保护网,当用户忘记显式释放相关资源,finalize()方法可以完成这一收尾工作,尽管finalize()方法不一定会被执行,但是有可能会释放资源总比永远不会释放资源更安全。



