为什么不';t类是Java中的第一类对象吗?

为什么不';t类是Java中的第一类对象吗?,java,generics,Java,Generics,有人能给我解释一下为什么类不是Java中的第一类对象吗?如果有,某些模式会很好地工作,我一直在用getter和setter编写工厂类,只是在类中添加了不必要的cruft,这样我就可以把实例传递给方法,而不是实际的类,从而分解出通用的代码位。例如: public class AsyncBookSearch extends AsyncTask<String,BookItem,Void> { public ListView list; public AmazonItemA

有人能给我解释一下为什么类不是Java中的第一类对象吗?如果有,某些模式会很好地工作,我一直在用getter和setter编写工厂类,只是在类中添加了不必要的cruft,这样我就可以把实例传递给方法,而不是实际的类,从而分解出通用的代码位。例如:

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;
    }
}

目前我不能用Java编写这样的代码。我必须在几乎所有涉及的类中引入不必要的耦合,这只会使事情变得更加复杂,因为现在不仅每个实例需要担心它自己的状态,而且还需要担心与它的任务完全无关的对象中的状态。

类是Java中的第一类对象(类中的)。您可以将它们分配给变量、传递、从函数返回等等。我想您是想问一些其他问题,但我不确定那个问题可能是什么。也许是关于泛型类型的擦除和具体化?对此的答案可能很有趣

一个你一直在写的粗俗的例子可能会有所帮助

同样,考虑“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。在方法调用期间,您实际上可以动态修改现有类或替换其方法。

我不认为您的问题真正是关于类的定义“第一类”对象。我怀疑这确实与java如何处理泛型有关。 我认为您需要理解类型擦除:在您的示例中,您基本上希望编写如下内容

void foo<T>{
  T bar = new T();
}
void foo{
T bar=新的T();
}
但这是不可能的,因为在运行时,没有关于T类实际是什么的信息,因为:

在实例化泛型类型时, 编译器通过 一种称为类型擦除的技术-a 编译器删除所有 与类型参数相关的信息 和类或类中的类型参数 类型擦除支持Java 使用泛型的应用程序 保持与的二进制兼容性 Java库和应用程序 是在泛型之前创建的


类是第一类。它们是类的对象。它们可以分配给变量和字段,作为参数传递,甚至可以动态创建

您面临的问题是泛型类型没有具体化,它们只在编译时可见。此外,由于构造函数不是继承的,除非您确切知道要创建哪个类,否则无法知道是否存在具有所需参数的构造函数。解决此问题的一种方法是传入f工厂班

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;
    }
}
公共类AsyncItemSearch扩展了AsyncTask{
公共列表视图列表;
公共适配器;
公共通用搜索工厂;
公共AsyncBookSearch(ListView l、AmazonimaDapter ad、GenericItemSearchFactory){
列表=l;
适配器=ad;
这个工厂=工厂;
}
@凌驾
受保护的Void doInBackground(字符串…关键字){
this.factory.getInstance(关键字[0],列表,适配器).parse();
返回null;
}
}

< /代码> 我不认为类是第一类对象,相反,我会说<代码>类< /代码>是反射API的一部分,因为你不能像其他更动态的语言那样自由地使用它。也就是说,你不能在没有反射的情况下创建新的实例。 主要原因是java的元模型。您不能覆盖静态方法,并且类中存在的构造函数不一定存在于其子类中。这也是您的代码
new t(关键字[0],列表,适配器)
无法工作的原因,子类可能没有这样的构造函数

因此,在java中,类对象没有任何用处,因为您肯定需要反射来检查代码在运行时是否有效

另一个主题是泛型类型参数。您不能执行
t.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;
    }
}
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
     }
}
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", "!");