搜索
您的当前位置:首页正文

对象的发布与逸出

来源:二三娱乐
对象的发布

“发布对象”指的是使对象能够在当前作用于之外的代码中使用

例如,将一个指向该对象的引用保存到其他代码可以访问的地方(情况一),或者在某一个非私有的方法中返回该引用(情况二),或者将引用传递到其他类的方法中(情况三)。

//情况一
public class Person(){
    private String name;
    private int age;
}

public class Record{
    Person p;
}

//情况二
public class Person(){
    private String name;
    private int age;

    public Person get(){
        return new Person();
    }
}

//情况三
public class Person(){
    private String name;
    private int age;
}

public class Record{
    private void getPersonMessage(Person p){
        .....
    }
}
对象逸出

当某个不应该发布的对象被发布时,这种情况就被称为“对象逸出”。

常见的对象逸出:

  • 内部的可变状态逸出
class UnsafeStates{
    private String[] states = {"AK","AL",...};
    public String[] getStates(){
        return states;
    }
}

如上,数组states本事私有的变量,但是以public公有的方式发布出去,导致states已经逸出了它所在的作用域,任何调用者都能修改这个数组的内容。

  • 隐式地使this引用逸出
public class ThisEscape{
    public ThisEscape(EventSource source){
        source.registerListener(
            new EventListener(){
                public void onEvent(Event e){
                    dosomething(e);
                }
            })
    }
}

实际上,这里是需要发布内部类实例,而这样的做法导致当ThisEscape发布EventListener时,也隐含地发布了ThisEscape实例本身。因为在这个内部类的实例中包含了对ThisEscape实例的隐含引用。

这样的逸出会出现什么问题呢?

public class ThisEscape{
    private int count;
    public ThisEscape(EventSource source){
        source.registerListener(
            new EventListener(){
                public void onEvent(Event e){
                    dosomething(e);
                }
            })
        //在这里count初始化为1
        count = 1;
    }
}

举个例子,如上,我们知道this逸出会导致ThisEscape也发布出去,也就是ThisEscape还没有构建完成就发布出去,也就是count=1;这一句还没执行就发布了ThisEscape对象,如果要使用count时,很有可能会出现对象不一致的状态。

那么如何解决这个问题呢?
使用工厂方法来防止this引用在构造函数过程中逸出

public class SafeListener{
    private final EventListener listener;

    private SafeListener(){
        listener = new EventListener(){
            public void onEvent(Event e){
                dosomething(e);
            }
        };
    }

    public static SafeListener newInstance(EventSource source){
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

如此,便能保证在对象为构造完成之前,是不会发布该对象。

Top