1理解类成员
类成员是属于整个类的,而不是属于对象的。因此创建一个对象时,只会为实例变量分配内存,而不会为类成员变量分配内存,类成员变量是在类初始化时分配的内存(执行main()方法之前),所以当类变量初始化以后,实例变量很可能还没有分配内存,因此类成员是不能访问实例变量的。
Java中对象可以访问类成员变量(很多语言是不允许对象访问类变量的),一般都是通过类来访问对象。
public class NullAccessStatic
{
private static void test()
{
System.out.println("static修饰的类方法");
}
public static void main(String[] args)
{
// 定义一个NullAccessStatic变量,其值为null
NullAccessStatic nas = null;
//使用null对象调用所属类的类方法
//下面代码一切正常,可以使用空对象访问类成员,进一步说明类成员是属于类的,其并不在对应实例中
nas.test();
}
}
//注意:如果一个null对象访问实例成员,将会引发NullPointException异常,
//因为null表明该实例根本不存在,既然实例不存在,它的实例成员也就不存在。
2 单例类
大部分时候把类的构造器访问控制权限都定义为public,允许任何类自由创建该类的对象。但在某些时候,允许其他类自由创建该类对象没有任何意义,还可能造成系统性能下降(因为频繁的创建对象,且回收对象会带来系统开销问题),这是就需要引入单例类了。如果一个类始终只能创建一个类,则这个类就被称为单例类。
要实现单例类需要做哪些处理:
- 将类的构造器隐藏起来,用private,但又需要创建一个对象,就需要提供一个public方法,用于创建该对象,且该方法必须使用static修饰(因为调用该方法之前还不存在对象,因此调用该方法的只能是类)
- 除此之外,还需要缓存已经创建好的对象,否则无法知道曾经是否创建过对象,也就无法保证只创建一个对象。为此该类需要提供一个成员变量来保存曾经创建过的对象,因为该成员变量需要被上面的方法调用,故该成员变量不许用static修饰。
class Singleton
{
////使用一个类成员变量来缓存曾经创建过的实例
private static Singleton instance;
//对构造器使用private修饰,隐藏该构造器
private Singleton(){}
// 提供一个静态方法,用于返回Singleton实例
//该方法可以加入自定义控制,保证指残生一个Singleton对象
public static Singleton getInstance()
{
// 如果instance为null,则表明不曾创建Singleton对象
//如果instance不为null,则表明已经创建过Singleton对象
// 将不会创建新的实例
if (instance == null)
{
// 创建一个Singleton对象,将其缓存起来
instance = new Singleton();
}
return instance;
}
}
public class SingletonTest
{
public static void main(String[] args)
{
//创建Singleton对象不能通过构造器
//只能通过getInstance方法来得到实例
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2); //将输出true
}
}
由上面代码可以看出,SingletonTest类的main方法中,看到两次产生的Singleton对象实际上就是同一对象。(这就是封装的优势,不允许自由访问类的成员变量和实现细节,而是通过方法来控制合适暴露。表面上是创建了两个对象,实际通过内部处理,实际是同一个对象)