我定期使用Eclipse调试器,这一直使我对IDE感到困惑.步进过滤是一种非常宝贵的工具,因此,我不会进入没有源代码的类,或者根本就不感兴趣.但是,在大多数情况下,Eclipse并没有做到这一点.特别是,有“过滤简单的getters”和“过滤简单的setters”选项.
我可能会使用仅返回成员变量值的getter.
private String value;
public String getValue()
{
return value;
}
或者是一个懒惰地实例化一个昂贵对象的吸气剂.
private IObjectFactory instance;
public IObjectFactory getInstance()
{
if (instance == null)
instance = ObjectFactory.createFactory();
return instance;
}
我可能会使用只设置成员变量值的设置器.
private String value;
public void setValue(String value)
{
this.value = value;
}
我可能想支持流利的语法.
private String value;
public ObjectFactory setValue(String value)
{
this.value = value;
return this;
}
或进行一些验证或事件触发.
private String user;
public void setUser(String user)
{
if (StringUtils.isBlank(user))
throw ExceptionHelper.argumentNull("user");
this.user = user;
}
private String title;
public void setTitle(String title)
{
if (!StringUtils.equals(this.title, title))
{
this.title= title;
onPropertyChanged("title", title);
}
}
对于这些用途中的每一种,都使用eclipse步骤进入这些方法来进入代码…
Eclipse将什么视为“简单获取器”或“简单设置器”?
筛选器肯定已启用:
如果有问题,我正在使用Eclipse Kepler build 20130614-0229.我正在使用JRE6运行Eclipse和托管Java 1.4 Web应用程序的Tomcat 7服务器.尽管最终目标是1.4,但它是使用JDK6在本地编译的,因此我认为这不是问题.我确实已经安装并使用了JRebel,也许类加载器正在干扰确定什么被认为是“简单”的算法?结合启用“逐步筛选”选项,它可能正在逐步遍历我的代码.考虑这一点后,我将做进一步的实验.
解决方法:
好吧,我想我已经找到了.
在正常情况下,如果启用了这些过滤器,则将跳过普通的获取器和普通的设置器(问题中的示例1和3).如果安装并使用了特殊的类加载器(例如JRebel)来修改要挂接到它们的方法,则它似乎会干扰Eclipse的算法,后者确定方法是“简单getter”还是“简单setter”.
因此,在代码中看起来像这样的getter:
public String getValue()
{
return this.value;
}
从JVM的角度来看,可以更改为如下所示:
public String getValue()
{
Proxy proxy = getProxy(this);
return (String)proxy.invoke("getValue", new Object[] { });
// this is all just an example,
// it's defintely way more complicated than this
}
这段经过修改的代码使Eclipse陷入思考“这不是一个简单的getter,因此请踏入它”.确实可以,但是实际的源代码是我的实际简单的getter,然后使我感到困惑:“为什么Eclipse进入了这个简单的getter?”
我进行了一个非常人为设计的测试,以尝试使步骤筛选起作用.
import org.apache.commons.lang.StringUtils;
public class Program
{
public static void main(String[] args)
{
User bob = new User("0001", "Bob");
String id = bob.getId(); //stepped over
String name = bob.getName(); //stepped over
IHome home = bob.getHome(); //stepped into
bob.setId("foo"); //stepped into
bob.setName("Bobby"); //stepped over
String asString = bob.setNameFluent("Bobbo").toString(); //stepped into
IHome newHome = Neighborhood.getHome("moo");
bob.setHome(newHome); //stepped into
return;
}
static class User
{
private String id;
private String name;
private IHome home;
public User() { this("0001", null); }
public User(String id, String name) { this.id = id; this.name = name; }
public String getId() // simple
{
return id;
}
public String getName() // simple
{
return name;
}
public IHome getHome() // not simple
{
if (home == null)
home = Neighborhood.getHome(id);
return home;
}
public void setId(String id) // not simple
{
if (StringUtils.isBlank(id))
throw ExceptionHelper.argumentBlank("id");
this.id = id;
}
public void setName(String name) // simple
{
this.name = name;
}
public User setNameFluent(String name) // not simple
{
this.name = name;
return this;
}
public void setHome(IHome home) // not simple
{
if (home != null)
{
this.home = home;
onHomeChanged();
}
}
protected void onHomeChanged()
{
this.id = home.getId();
}
public String toString()
{
return "User { name=" + getName() + ", home=" + getHome() + " }";
}
}
static interface IHome
{
String getId();
String getLocation();
}
static class Neighborhood
{
public static IHome getHome(String id)
{
return new Home(id);
}
static class Home implements IHome
{
private String id;
public Home(String id) { this.id = id; }
public String getId() { return id; }
public String getLocation() { return "Home" + id; }
public String toString() { return "Home: " + getLocation(); }
}
}
static class ExceptionHelper
{
public static IllegalArgumentException argumentBlank(String name)
{
return new IllegalArgumentException("Argument " + name + " must not be blank");
}
}
}
使用默认配置(不带JRebel的JDK6),步骤筛选似乎可以正常工作.尝试进入简单方法实际上已跨过它们.在启用JRebel并再次单步执行代码之后,它逐步进入了所有方法.而且,是否启用了“逐步通过过滤器”也没关系.
tldr;
通过使用JRebel,它确实使Eclipse困惑,使简单的getter和简单的setter看起来比原来更加复杂.禁用JRebel将导致过滤器按预期工作.