有人可以向我解释为什么类不是Java中的第一类对象吗?有一些模式可以很好地工作,如果它和我一直在编写带有getter和setter的工厂类,只是添加不必要的类,这样我就可以将实例传递给方法而不是实际的类来分解泛型代码。例如:
public class AsyncBookSearch extends AsyncTask<String,BookItem,Void> {
public ListView list;
public AmazonItemAdapter<BookItem> adapter;
public AsyncBookSearch(ListView l,AmazonItemAdapter<BookItem> ad) {
list = l;
adapter = ad;
}
@Override
protected Void doInBackground(String... keywords) {
// TODO Auto-generated method stub
new BookSearch(keywords[0],list,adapter).parse();
return null;
}
}
我有几个这样的类,如果我想让整个事物变得通用,那么doInBackground()
中的东西会导致几个额外的方法和参数传递中的其他类型的重复,如果我不是问题可写下面的内容:
public class AsyncItemSearch<T extends GenericItemSearch<S>,S extends GenericItem> extends AsyncTask<String,T,Void> {
public ListView list;
public AmazonItemAdapter<S> adapter;
public AsyncBookSearch(ListView l,AmazonItemAdapter<S> ad) {
list = l;
adapter = ad;
}
@Override
protected Void doInBackground(String... keywords) {
// TODO Auto-generated method stub
new T(keywords[0],list,adapter).parse();
return null;
}
}
目前我无法在Java中编写类似的代码。我必须在所涉及的每个类中引入不必要的耦合,这只会使事情变得更加复杂,因为现在不仅每个实例都需要担心它自己的状态,而且还需要关注与它的任务完全无关的对象中的状态。
答案 0 :(得分:9)
我不认为你的问题实际上是关于类是“第一类”对象。我怀疑它与java如何处理泛型有关。 我认为你需要理解类型擦除:在你的例子中,你基本上想写一些类似
的东西void foo<T>{
T bar = new T();
}
但这是不可能的,因为在运行时,由于type erasure,没有关于T实际上是什么的信息:
实例化泛型类型时, 编译器通过转换这些类型 一种称为类型擦除的技术 - a 编译器删除所有的进程 与类型参数相关的信息 并在类或中键入参数 方法。类型擦除启用Java 使用泛型的应用程序 保持二进制兼容性 Java库和应用程序 是在仿制药之前创建的。
答案 1 :(得分:2)
类是Java(类Class)中的第一类对象。你可以将它们分配给变量,传递,从函数返回等。我想你想问一些其他问题,但我不确定那个问题是什么。也许关于擦除与泛型类型的具体化有关?答案可能很有趣。
你写作的一个例子可能有所帮助。
另外,考虑一下这个问题之间的区别,比如'X有原因吗'和'X有很好的用途'。
编辑:(回答评论:“我还没有看到一个类传递的例子”(顺便说一句:我仍然认为这是关于擦除与具体化的问题,但这个具体的评论确实如此)没有解决它。)我很惊讶你没有。用Java传递类是很常见的。很少有真正流行的API的例子在我不假思索的情况下出现在我的脑海中:
Hibernate / JPA实体管理器根据其类及其主键查找映射对象;例如:Invoice i = entityManager.find(Invoice.class, 12l)
GWT使用特殊工厂来注入仅存在于生成的javascript中的类(或以其他方式参数化);该方法采用类的实例来创建;例如:Resource res1 = GWT.create(MyResources.class);
Spring的ApplicationContext根据您传递给getBean方法的类为您提供bean;所以你会这样做:DataSource default = applicationContext.getBean(DataSource.class);
在少数情况下使用类实例,当C#使用反射时(Java不能,因为它在运行时擦除泛型类型);该模式有时被称为“类令牌”
在上面的大多数情况下,您将看到类文字(作为第一类对象类在Java中具有文字)而不是动态调用,但这主要是因为语言的静态性质(以及程序员的静态性质)用它)。在编译时知道你的类型通常被认为是一件好事。
由于Java在运行时不支持泛型,因此无法即时创建泛型类。这没有区别,因为您可以创建一个非泛型类并将其用作通用类。
回答另一条评论:通常使用在运行时创建和修改类,但主要是由Java基础结构使用:应用程序服务器,库。看看JMockit。实际上,您可以修改现有类或在方法调用期间动态替换其方法。
答案 2 :(得分:2)
课程是一流的。它们是Class类的对象。它们可以分配给变量和字段,作为参数传递,甚至可以动态创建。
您遇到的问题是泛型类型未实现,它们仅在编译时可见。此外,因为构造函数不是继承的,除非您确切地知道要创建哪个类,否则您无法知道是否存在具有所需参数的构造函数。解决您遇到的问题的一种方法是通过工厂类。
public class AsyncItemSearch<T extends GenericItemSearch<S>,S extends GenericItem> extends AsyncTask<String,T,Void> {
public ListView list;
public AmazonItemAdapter<S> adapter;
public GenericItemSearchFactory<T> factory;
public AsyncBookSearch(ListView l,AmazonItemAdapter<S> ad, GenericItemSearchFactory<T> factory) {
list = l;
adapter = ad;
this.factory = factory;
}
@Override
protected Void doInBackground(String... keywords) {
this.factory.getInstance(keywords[0],list,adapter).parse();
return null;
}
}
答案 3 :(得分:2)
我不认为类是第一类对象,而是我会说Class
是反射API的一部分,因为你不能像其他更动态的语言一样自由地使用它。即你不能在没有反射的情况下创建新的实例。
主要原因是java的元模型。您不能覆盖静态方法,并且类中存在的构造函数不一定存在于其子类中。这也是您的代码new T(keywords[0],list,adapter)
不起作用的原因,子类可能没有这样的构造函数。
因此,在java中,没有使用类对象,因为你肯定需要反射来检查你的代码在运行时是否有效。
不同的主题是泛型类型参数。你不能做T.class
,因为genrics在某种程度上是java中的语言破解(与C ++模板相比没什么)。其主要原因是与旧版Java兼容。
但是,您可以使用上面提到的反射API解决此问题:
public Foo<T extends Bar> {
private Class<T> barClass;
public Foo(Class<T> barClass) {
this.barClass = barClass;
}
public T createSomeBar(String arg) {
try {
// the bar contract says that subclasses must have such a constructor
return barClass.getConstructor(String.class).newInstance(arg);
} catch ... // the contract was violated, do proper handling
}
}
答案 4 :(得分:1)
课程是一流的项目。您可以在类上调用“newinstance”方法来创建实例,也可以请求构造函数对象并使用它。试试这段代码:
public class AsyncItemSearch<T extends GenericItemSearch<S>,S extends GenericItem> extends AsyncTask<String,T,Void> { private Constructor<T> searchConstructor; public ListView list; public AmazonItemAdapter<S> adapter; public AsyncBookSearch(Class<T> theClass, ListView l,AmazonItemAdapter<S> ad) { list = l; adapter = ad; searchConstructor = theClass.getConstructor(String.class, ListView.class, AmazonItemAdapter<S>.class); } @Override protected Void doInBackground(String... keywords) { // TODO Auto-generated method stub searchConstructor.newInstance(keywords[0],list,adapter).parse(); return null; } }
这样称呼:
AmazonItemAdapter<Book> amazonAdapter = new AmazonBookAdapter(); AsyncItemSearch<BookSearch,Book> s = new AsyncItemSearch<BookSearch,Book>( BookSearch.class, myListView, amazonAdapter ); s.doInBackground("have", "at", "thee", "!");