Inherit from any subclass of the superclass (Java)

I'm just a C ++ programmer, and in C ++ I could do something like this:

class SuperSuper { virtual void newItem()=0; } class SubSuperA:public SuperSuper { virtual void newItem() { //do something } } class SubSuperB:public SuperSuper { virtual void newItem() { //do something different (disappear! :) } } template <class T> class SubSub:public T { virtual void newItem() { T::newItem(); //do a third thing } } 

I want to do it in Java, but I feel that it is (at least directly) impossible

I easily install the first three classes in Java as follows:

 public abstract class SuperSuper { abstract void newItem(Item item); } public class SubSuperA extends SuperSuper { @Override void newItem(Item item) { //stuff } } public class SubSuperB extends SuperSuper { @Override void newItem(Item item) { //other stuff } } //SubSuperC,D,etc 

And currently I'm implementing the fourth one like this:

 SubSuperA sa=new SubSuperA() { @Override public void newItem(Item item) { super.newItem(item); //A lot of stuff that will be changing constantly throughout development } }; SubSuperB sb=new SubSuperB() { @Override public void newItem(Item item) { super.newItem(item); //A lot of stuff that will be changing constantly throughout development } }; 

Note that both of the overrides have the same function. No matter what SubSuper * is based on, the replacement of newItem () is identical. Obviously, this will be a nightmare to maintain. I was hoping I could just declare a SubSub class as follows

  public class SubSub<T> extends T { @Override public void newItem(Item item) { super.newItem(item); //A lot of stuff that will be changing constantly throughout development } } 

that I could just create such an instance

  SubSub ss=new SubSub<SubSuperA> 

etc, but these errors in java:

 "Cannot refer to the type parameter T as a supertype." 

I looked around this error and found Extend from Generic Supertype? who claims that what I want to do is not possible with this method.

Actually I need to do: I have a client agent that simply processes tweets, saving them, etc. It has an abstract column class (SuperSuper) that I can extend for different types of columns (SubSuper) (home history, mentions, etc.), and each filters out the tweets that they want to display in newItem (). I want to be able to connect different graphical interfaces to it for different platforms, and I need the client to call a special GUI function (SubSub) to process each individual tweet in the graphical interface library. Having a special GUI class that can extend any column-based class would be an ideal solution

Since this direct implementation seems to be impossible in Java, I wonder if there is some kind of syntax trick that will achieve something pretty similar, or if I just have to stop creating an interface that will be stored and called by SuperSuper and SuperSub * and implemented by my GUI handler instead of SubSub.

+4
source share
3 answers

Templates are possible using Java generics. However, in Java, interfaces are much more popular than inheritance. This is because Java does not support multiple inheritance.

In C ++, you can extend several classes.

 class X : public A, public B, private C { } 

Since C ++ makes no distinction between virtual and non-virtual classes, only virtual and non-virtual members, there is no formal difference between classes that may or may not have virtual methods.

Java, on the other hand, has three different types of classes:

  • Concrete (completely non-virtual, all methods specific)
  • Abstract (partially virtual, partially not virtual)
  • Interface (fully virtual, without specific methods)

In Java, virtual methods are called abstract methods, so I will call them here.

Java also has generics. Generics are similar to templates syntactically, but completely different in terms of implementation. I will leave the introduction study to you (the keyword to use in your search is β€œerasure”).

Designations are declared in the class. For example, Java, the equivalent of C ++ vector , is an ArrayList class. Its use is very similar:

 List<String> strs = new ArrayList<String>(); 

Here, List is a kind of supertype of ArrayList . List is an interface, and ArrayList implements it. List itself declares a generic type in its declaration like this:

 public interface List<E> ... { // ... E get(int index); // ... } 

Notice how get returns E Here E not defined specifically. This is a generic type, in which case you can use anything in its place, String , Object , Boolean , your own classes, etc.

ArrayList implements List , and also declares a generic type:

 public ArrayList<E> implements List<E>, ... { // ... public E get(int index) { // bounds check return elements[i]; } // ... } 

You can also restrict types to generics using type restrictions. This is a bit beyond that, since what you want is not really generics. You need interfaces.

In your example, you first declare an interface with newItem .

 public interface A { void newItem(); } 

Each method should come from a specific implementation or interface, hence the need for this interface. In particular, this interface will be equivalent to SuperSuper . This is a fully virtual class (interface). Now for your classes:

 public class B implements A { @Override public void newItem() { // Do something } } public class C implements A { @Override public void newItem() { // Do something else } } 

Your last bit is a bit confusing to someone like me without much experience with C ++, but I assume that you say that you want to create a template type using the newItem method. In Java, this will be another implementation of the A interface, or you can extend B or C and override their methods.

 public class D extends B { @Override public void newItem() { // And yet another something else } } 

Then using something with the newItem method is as simple as:

 A a = new B(); // or "new C()" or "new D()" a.newItem(); 

Just as you can say

 SuperSuper* a = new SubSuperA(); 

In Java, you can do the same with interfaces, abstract classes, and concrete classes, as I did above.

So, I believe interfaces are the solution to your problem. I highly recommend reading how interfaces are used in Java. They provide powerful typing with no multiple inheritance. I will find a couple of links very quickly.

I hope for help. Let me know if you need any clarification.

+2
source

You can not.

C ++ templates are really the source code for templates. When you have a class or template function, for each type used as a type argument, the compiler efficiently generates ("instantiates") a separate copy of the source code with the type parameter replaced by the actual type argument. So, for example, vector<int> and vector<string> are completely separate types, and the compiled code for their functions can also be separate (just as if they were separate types).

This is why it is possible to do this in the same way as inheriting from a type parameter. For the compiler, it simply replaces any argument of type T wherever it sees it. The resulting code is valid, so it works.

Java generics are very different. There is only one copy of the compiled code for a common class or method. One version of the compiled code should at the same time work for any possible type parameter (existing or future) that falls within its boundaries.

So, think what it would mean if you could do what you offer. There is only one copy of the compiled code for the SubSub class, and it inherits, well, T , whatever that is. Therefore, it must simultaneously inherit each type. How is this possible? A class can have only one, specific, parent class.

+1
source

Based on your Java code, I think you really need a decorator pattern:

 public class SubSub<T extends SuperSuper> extends SuperSuper { private final Class<T> clazz; public SubSub(Class<T> clazz){ this.clazz = clazz; } @Override public void newItem(Item item){ T sup = clazz.newInstance(); sup.newItem(item); // other stuff } } 

With calls like:

 SubSub<SubSuperA> foo = new SubSub<SubSuperA>(SubSuperA.class); 

You can completely get rid of generics if, say, you just wanted to pass the class name as a parameter:

 public class SubSub extends SuperSuper { private final SuperSuper _super; public <T extends SuperSuper> SubSub(Class<T> clazz){ _super = clazz.newInstance(); } @Override public void newItem(Item item){ _super.newItem(item); sup.newItem(item); // other stuff } } 

With view instantiation:

 SubSub foo = new SubSub(SubSuperA.class); 

or

 SubSub foo = new SubSub((Class<SuperSuper>) Class.forName("SubSuperA")); 
0
source

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


All Articles