Java 为什么firePropertyChange(字符串propertyName、对象oldValue、对象newValue)受保护而不是公共的?

Java 为什么firePropertyChange(字符串propertyName、对象oldValue、对象newValue)受保护而不是公共的?,java,swing,event-handling,jcalendar,Java,Swing,Event Handling,Jcalendar,问题是,我正在从库中开发一个IDateEditor接口实现,我注意到该方法不是公共的,而是受保护的。情况如下: public class DateFormattedTextField implements IDateEditor { private JFormattedTextField editor; private DateUtil dateUtil; ... @Override public void setDate(Date

问题是,我正在从库中开发一个
IDateEditor
接口实现,我注意到该方法不是公共的,而是受保护的。情况如下:

public class DateFormattedTextField implements IDateEditor {

    private JFormattedTextField editor;        
    private DateUtil dateUtil;

    ...

    @Override
    public void setDate(Date date) {
        Date oldDate = (Date)editor.getValue();            
        if(dateUtil.checkDate(date)){
            editor.setValue(date);
            editor.firePropertyChange("date", oldDate, date); // <-- error here
        }
    }

}
公共类DateFormattedTextField实现IDateEditor{
私有JFormattedTextField编辑器;
私有DateUtil-DateUtil;
...
@凌驾
公共作废设置日期(日期){
Date oldDate=(Date)editor.getValue();
if(dateUtil.checkDate(日期)){
编辑器.设置值(日期);

firePropertyChange(“date”,oldDate,date);//更改通知是任何可观察对象(通常是java bean)的固有责任:如果在其绑定属性发生更改时不触发PropertyChangeEvent,则会违反其合同。在这种情况下,任何其他方都不需要使用fireXX方法


因此,范围比受保护的范围更广是没有任何意义的。如果你觉得需要它,你就做错了。

我添加这个答案只是为了完整性。在@kleopatra明智的解释和评论之后,我意识到我混淆了概念和责任。在这种情况下,属性更改通知作为底层编辑器组件使用的
JFormattedTextField
不负责初始化,而是
IDateEditor
实现本身的责任

因此,为了实现我用来保存属性更改侦听器列表的接口,并通过以下方式通知它们:

正如您所见,添加/删除
PropertyChangeListeners
并在属性更改事件中通知他们的任务被委托给
PropertyChangeSupport
类成员,但事件的源是
this
,即
IDateEdit
接口实现者。正如@kleopatra所说,这是客户端的源应该是事件的源,而不是参考线编辑器组件

下面是生成类的完整代码(很抱歉进行了扩展)。如果您愿意,请随意使用/修改或玩它

/**
 * Custom implementation of {@code IDateEditor} interface. Unlike the default 
 * implementation provided with JCalendar library, this won't allow invalid 
 * inputs of any kind from the user.
 * 
 * @author dic19
 */
public class DefaultDateEditor implements IDateEditor {

    private Date date;
    private String dateFormatString;
    private Locale locale;
    private SimpleDateFormat dateFormat;
    private final DateFormatter dateFormatter;
    private final JFormattedTextField editor;
    private final DateUtil dateUtil;
    private final PropertyChangeSupport propertyChangeSupport;

    public DefaultDateEditor() {
        date = new Date();
        dateUtil = new DateUtil();
        propertyChangeSupport = new PropertyChangeSupport(this);
        addPropertyChangeListener("dateFormatString", new DateFormatStringChangeListener());
        addPropertyChangeListener("locale", new LocaleChangeListener());

        dateFormatString = "yyyy-MM-dd HH:mm:ss";
        locale = Locale.getDefault();
        dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
        dateFormat.applyPattern(dateFormatString);

        dateFormatter = new DateFormatter();
        dateFormatter.setCommitsOnValidEdit(true);
        dateFormatter.setAllowsInvalid(false);
        dateFormatter.setOverwriteMode(true);

        editor = new JFormattedTextField();
        editor.setValue(date);
        editor.setColumns(15);
        editor.setToolTipText(dateFormatString);
        editor.addPropertyChangeListener("value", new EditorValueChangeListener());

        installFormatterFactoryOnEditor();
    }

    private void installFormatterFactoryOnEditor() {
        dateFormatter.setFormat(dateFormat);
        DefaultFormatterFactory factory = editor.getFormatterFactory() instanceof DefaultFormatterFactory
                                        ? (DefaultFormatterFactory) editor.getFormatterFactory()
                                        : new DefaultFormatterFactory();
        factory.setDefaultFormatter(dateFormatter);
        factory.setDisplayFormatter(dateFormatter);
        factory.setEditFormatter(dateFormatter);
        factory.setNullFormatter(dateFormatter);
        editor.setFormatterFactory(factory);
    }

    @Override
    public Date getDate() {
        return date != null ? new Date(date.getTime()) : null;
    }

    @Override
    public void setDate(Date date) {
        if (dateUtil.checkDate(date)) {
            Date oldValue = this.date;
            this.date = date != null ? new Date(date.getTime()) : null;
            editor.setValue(this.date);
            firePropertyChangeEvent("date", oldValue, date);
        }
    }

    @Override
    public void setDateFormatString(String dateFormatString) {
        String oldDateFormat = this.dateFormatString;
        this.dateFormatString = dateFormatString;
        firePropertyChangeEvent("dateFormatString", oldDateFormat, dateFormatString);
    }

    @Override
    public String getDateFormatString() {
        return dateFormatString;
    }

    @Override
    public void setSelectableDateRange(Date min, Date max) {
        dateUtil.setSelectableDateRange(min, max);
    }

    @Override
    public Date getMaxSelectableDate() {
        return dateUtil.getMaxSelectableDate();
    }

    @Override
    public Date getMinSelectableDate() {
        return dateUtil.getMinSelectableDate();
    }

    @Override
    public void setMaxSelectableDate(Date max) {
        dateUtil.setMaxSelectableDate(max);
    }

    @Override
    public void setMinSelectableDate(Date min) {
        dateUtil.setMinSelectableDate(min);
    }

    @Override
    public JComponent getUiComponent() {
        return editor;
    }

    @Override
    public void setLocale(Locale locale) {
        Locale oldLocale = this.locale;
        this.locale = locale;
        firePropertyChangeEvent("locale", oldLocale, locale);
    }

    @Override
    public void setEnabled(boolean enabled) {
        editor.setEnabled(enabled);
    }

    @Override
    public final void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    @Override
    public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }

    @Override
    public final void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    @Override
    public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }

    public final PropertyChangeListener[] getPropertyChangeListeners() {
        return propertyChangeSupport.getPropertyChangeListeners();
    }

    public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
        return propertyChangeSupport.getPropertyChangeListeners(propertyName);
    }

    protected final void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

    private class EditorValueChangeListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("value".equals(evt.getPropertyName())) {
                System.out.println("Old value:" + evt.getOldValue());
                System.out.println("New value:" + evt.getNewValue());
                setDate((Date)evt.getNewValue());
            }
        }
    }

    private class DateFormatStringChangeListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("dateFormatString".equals(evt.getPropertyName())) {
                dateFormat.applyPattern(dateFormatString);
                editor.setToolTipText(dateFormatString);
                installFormatterFactoryOnEditor();                    
            }
        }
    }

    private class LocaleChangeListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("locale".equals(evt.getPropertyName())) {
                dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
                dateFormat.applyPattern(dateFormatString);
                editor.setLocale(locale);
                installFormatterFactoryOnEditor();
            }
        }
    }
}

因为变更通知是编辑的固有责任——其他人不应该这样做interfere@kleopatra您需要回答这个问题!在您的实现中有一个小错误:向某个对象添加侦听器的客户端希望该对象作为事件源,所以干净地路由到某个委托意味着拦截任何通知rom代表,并在将源设置为itself@kleopatra感谢您指出这一点,我会记住:)您好!谢谢您的回答:)这对我来说完全有意义,但它会让我自动问为什么会有公共方法触发属性更改事件?例如:
public void firePropertyChange(字符串propertyName、双oldValue、双newValue)
。这些方法是从AWT继承的吗,之前是Swing?这些方法是为了向后兼容吗?我不认为我需要这个方法公共的,正如我所说的那样,我可以简单地从JFormattedTextField扩展我的类并解决问题。事实上,我认为这样做完全符合你的答案。设计意外?我的猜测与您的:-)顺便说一句,为什么要扩展JFormattedTextField?通常,JXX用于按原样使用,因此您在扩展时走错方向的概率为非零。。。
public class DateFormattedTextField implements IDateEditor {

    private JFormattedTextField editor;        
    private DateUtil dateUtil;
    private DateFormat dateFormat;
    private String dateFormatString;

    public DateFormattedTextField(){
        dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
        editor = new JFormattedTextField(dateFormat);
        editor.setColumns(10);
        editor.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
        dateUtil = new DateUtil();            
    }

    @Override
    public Date getDate() {
        return (Date)editor.getValue();
    }

    @Override
    public void setDate(Date date) {
        Date oldDate = (Date)editor.getValue();            
        if(dateUtil.checkDate(date)){
            editor.setValue(date);
            editor.firePropertyChange("date", oldDate, date); // <-- error here
        }
    }

    @Override
    public void setDateFormatString(String dateFormatString) {
        this.dateFormatString = dateFormatString;
    }

    @Override
    public String getDateFormatString() {
        return this.dateFormatString;
    }

    @Override
    public void setSelectableDateRange(Date min, Date max) {
        dateUtil.setSelectableDateRange(min, max);
    }

    @Override
    public Date getMaxSelectableDate() {
        return dateUtil.getMaxSelectableDate();
    }

    @Override
    public Date getMinSelectableDate() {
        return dateUtil.getMinSelectableDate();
    }

    @Override
    public void setMaxSelectableDate(Date max) {
        dateUtil.setMaxSelectableDate(max);
    }

    @Override
    public void setMinSelectableDate(Date min) {
        dateUtil.setMinSelectableDate(min);
    }

    @Override
    public JComponent getUiComponent() {
        return editor;
    }

    @Override
    public void setLocale(Locale locale) {
        editor.setLocale(locale); // to be reviewed
    }

    @Override
    public void setEnabled(boolean enabled) {
        editor.setEnabled(enabled);
    }

    @Override
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        editor.addPropertyChangeListener(listener);
    }

    @Override
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        editor.addPropertyChangeListener(propertyName, listener);
    }

    @Override
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        editor.removePropertyChangeListener(listener);
    }

    @Override
    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        editor.removePropertyChangeListener(propertyName, listener);
    }
}
public class DefaultDateEditor implements IDateEditor {
    ...
    private final JFormattedTextField editor;
    private final PropertyChangeSupport propertyChangeSupport;
    ...

    public DefaultDateEditor() {
        ...
        propertyChangeSupport = new PropertyChangeSupport(this);
        ...
        editor = new JFormattedTextField();
        ...
    }

    @Override
    public final void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    @Override
    public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }

    @Override
    public final void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    @Override
    public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }

    public final PropertyChangeListener[] getPropertyChangeListeners() {
        return propertyChangeSupport.getPropertyChangeListeners();
    }

    public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
        return propertyChangeSupport.getPropertyChangeListeners(propertyName);
    }

    protected final void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }
    ...
}
/**
 * Custom implementation of {@code IDateEditor} interface. Unlike the default 
 * implementation provided with JCalendar library, this won't allow invalid 
 * inputs of any kind from the user.
 * 
 * @author dic19
 */
public class DefaultDateEditor implements IDateEditor {

    private Date date;
    private String dateFormatString;
    private Locale locale;
    private SimpleDateFormat dateFormat;
    private final DateFormatter dateFormatter;
    private final JFormattedTextField editor;
    private final DateUtil dateUtil;
    private final PropertyChangeSupport propertyChangeSupport;

    public DefaultDateEditor() {
        date = new Date();
        dateUtil = new DateUtil();
        propertyChangeSupport = new PropertyChangeSupport(this);
        addPropertyChangeListener("dateFormatString", new DateFormatStringChangeListener());
        addPropertyChangeListener("locale", new LocaleChangeListener());

        dateFormatString = "yyyy-MM-dd HH:mm:ss";
        locale = Locale.getDefault();
        dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
        dateFormat.applyPattern(dateFormatString);

        dateFormatter = new DateFormatter();
        dateFormatter.setCommitsOnValidEdit(true);
        dateFormatter.setAllowsInvalid(false);
        dateFormatter.setOverwriteMode(true);

        editor = new JFormattedTextField();
        editor.setValue(date);
        editor.setColumns(15);
        editor.setToolTipText(dateFormatString);
        editor.addPropertyChangeListener("value", new EditorValueChangeListener());

        installFormatterFactoryOnEditor();
    }

    private void installFormatterFactoryOnEditor() {
        dateFormatter.setFormat(dateFormat);
        DefaultFormatterFactory factory = editor.getFormatterFactory() instanceof DefaultFormatterFactory
                                        ? (DefaultFormatterFactory) editor.getFormatterFactory()
                                        : new DefaultFormatterFactory();
        factory.setDefaultFormatter(dateFormatter);
        factory.setDisplayFormatter(dateFormatter);
        factory.setEditFormatter(dateFormatter);
        factory.setNullFormatter(dateFormatter);
        editor.setFormatterFactory(factory);
    }

    @Override
    public Date getDate() {
        return date != null ? new Date(date.getTime()) : null;
    }

    @Override
    public void setDate(Date date) {
        if (dateUtil.checkDate(date)) {
            Date oldValue = this.date;
            this.date = date != null ? new Date(date.getTime()) : null;
            editor.setValue(this.date);
            firePropertyChangeEvent("date", oldValue, date);
        }
    }

    @Override
    public void setDateFormatString(String dateFormatString) {
        String oldDateFormat = this.dateFormatString;
        this.dateFormatString = dateFormatString;
        firePropertyChangeEvent("dateFormatString", oldDateFormat, dateFormatString);
    }

    @Override
    public String getDateFormatString() {
        return dateFormatString;
    }

    @Override
    public void setSelectableDateRange(Date min, Date max) {
        dateUtil.setSelectableDateRange(min, max);
    }

    @Override
    public Date getMaxSelectableDate() {
        return dateUtil.getMaxSelectableDate();
    }

    @Override
    public Date getMinSelectableDate() {
        return dateUtil.getMinSelectableDate();
    }

    @Override
    public void setMaxSelectableDate(Date max) {
        dateUtil.setMaxSelectableDate(max);
    }

    @Override
    public void setMinSelectableDate(Date min) {
        dateUtil.setMinSelectableDate(min);
    }

    @Override
    public JComponent getUiComponent() {
        return editor;
    }

    @Override
    public void setLocale(Locale locale) {
        Locale oldLocale = this.locale;
        this.locale = locale;
        firePropertyChangeEvent("locale", oldLocale, locale);
    }

    @Override
    public void setEnabled(boolean enabled) {
        editor.setEnabled(enabled);
    }

    @Override
    public final void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    @Override
    public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }

    @Override
    public final void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    @Override
    public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }

    public final PropertyChangeListener[] getPropertyChangeListeners() {
        return propertyChangeSupport.getPropertyChangeListeners();
    }

    public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
        return propertyChangeSupport.getPropertyChangeListeners(propertyName);
    }

    protected final void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

    private class EditorValueChangeListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("value".equals(evt.getPropertyName())) {
                System.out.println("Old value:" + evt.getOldValue());
                System.out.println("New value:" + evt.getNewValue());
                setDate((Date)evt.getNewValue());
            }
        }
    }

    private class DateFormatStringChangeListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("dateFormatString".equals(evt.getPropertyName())) {
                dateFormat.applyPattern(dateFormatString);
                editor.setToolTipText(dateFormatString);
                installFormatterFactoryOnEditor();                    
            }
        }
    }

    private class LocaleChangeListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("locale".equals(evt.getPropertyName())) {
                dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
                dateFormat.applyPattern(dateFormatString);
                editor.setLocale(locale);
                installFormatterFactoryOnEditor();
            }
        }
    }
}