Why are Java classes not Java classes?

Can someone explain to me why classes are not first class objects in Java? There are certain patterns that would work very well if that were the case, and I constantly write factory classes with getters and setters and just adding extra cracks to the classes so that I can bypass the transfer methods instead of the methods and not the actual classes from the common bits code. For instance:

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

I have several such classes, and if I want to make all this general, the material in doInBackground() will lead to several additional methods and other types of duplication in passing arguments that would not be a problem if I could write the following:

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

Currently, I cannot write such code in Java. I have to introduce an unnecessary connection in almost every class, and this only makes things more confusing, because now not only each instance needs to worry about its own state, but also about the state of objects that are completely unrelated to it.

+4
source share
5 answers

I do not think your question is really about classes that are "first class" objects. I suspect this is really related to the way java handles generics. I think you need to understand the erasure of styles: in your example, you essentially want to write something like

 void foo<T>{ T bar = new T(); } 

but this is not possible, because at run time there is no information that the class is actually T, due to the erasure type :

When a typical type is generated, the compiler translates these types of methods, called erasing styles - a process when the compiler deletes all information related to type parameters and enter arguments inside the class or method. The erasure type allows Java applications that use binary compatibility support with Java libraries and applications that were created prior to generics.

+9
source

Classes are first class objects in Java (Class class). You can assign them to variables, pass, return from a function, etc. I think you wanted to ask another question, but I'm not sure what this question may be. Maybe something about the erasure and reification of the generic types? The answer to this may be interesting.

An example of what you keep writing can help.

Also, consider the difference between the question, for example, “Does X have a reason” and “Does X have a good use”.

EDIT: (replying to the comment: “I have not seen any examples of classes that are passed” (by the way, I still think this is a question about erasing or materializing, but this specific comment don’t refer to it). I am surprised that you They didn’t. Class passing in Java is very common. A few examples from the really popular APIs that appear in my head without hesitation:

  • The Hibernate / JPA Entity Administrator scans the associated object based on its class and its primary key; e.g. Invoice i = entityManager.find(Invoice.class, 12l)

  • GWT uses a special factory to inject classes that exist only in generated javascript (or otherwise parameterized); The method takes an instance of the class to create; for example: Resource res1 = GWT.create(MyResources.class);

  • Spring ApplicationContext gives you beans based on the class that you pass to the getBean method; so what would you do: DataSource default = applicationContext.getBean(DataSource.class);

  • Instance instances are used in rare cases when C # will use reflection (and Java cannot, since it erases common types at runtime); the template is sometimes called a "class token"

In most cases above, you will see a class literal (since first-class class classes have literals in Java), not a dynamic call, but mainly because of the static nature of the language (and the programmers who use this). It is generally considered good to know your types at compile time.

since Java does not support generics at run time, you cannot create a generic class on the fly. This doesn't make any difference since you can create a non-generic class and use it as a generic one.

Responding to another comment: the creation and modification of classes is usually used at runtime, but mainly using the Java infrastructure: application servers, libraries. Look at J. Mokkita. In fact, you can modify an existing class or replace its methods on the fly by the time the method is called.

+2
source

Classes are second to none. These are objects of class Class. They can be assigned to variables and fields, passed as arguments, and even created dynamically.

The problem you are facing is not typical types, they are only visible at compile time. In addition, since constructors are not inherited, unless you know exactly which class you want to create, you cannot know if a constructor exists with the arguments you need. One way to get around the problem you have is to go through the factory 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; } } 
+2
source

I would not consider classes as an object of the first class, instead I would say that Class is part of the reflection API, since you cannot use it as freely as in other, more dynamic languages. That is, you cannot create new instances without reflection.

The main reason is the Java metamodel. You cannot overwrite static methods, and the constructor that exists in the class does not necessarily exist in its subclasses. This is also the reason why your new T(keywords[0],list,adapter) code new T(keywords[0],list,adapter) does not work, subclasses may not have such a constructor.

Thus, in java, it makes no sense to use class objects, since you definitely need reflection to check if the code really is at run time.

Another topic is type parameters. You cannot make T.class , because genres are somehow hacked in Java (and nothing compared to C ++ Templates). The main reason for this is compatibility with older versions of Java.

However, you can workaround to use the reflection API mentioned above:

 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 } } 
+2
source

Classes are second to none. You can call the "newinstance" method in the class to create an instance, or you can request a constructor object and use it. Try this code:

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

Call it like this:

  AmazonItemAdapter <Book> amazonAdapter = new AmazonBookAdapter ();
 AsyncItemSearch <BookSearch, Book> s = 
     new AsyncItemSearch <BookSearch, Book> (
         BookSearch.class, myListView, amazonAdapter
     );
 s.doInBackground ("have", "at", "thee", "!");
+1
source

Source: https://habr.com/ru/post/1339715/


All Articles