check sub class with instanceof

I try this code to check if my class match with the subclass, but Processing say no, because my Class array is null or invalid I don't know :

void setup() {
  // if a class is an instance of creating class
   Child_1 c = new Child_1() ;

   for(int i = 0 ; i < child_class(this, "Mother").length ; i++) {
    if(c instanceof child_class(this, "Mother")[i] ) println(i, "yes") ;
   }
}

Class [] child_class(PApplet parent, String super_class_name) {
  Class[] c = parent.getClass().getDeclaredClasses();
  c = new Class[c.length -1] ;
  return c ;
}

class Mother {
  Mother() {}
}

class Child_1 extends Mother {
  Child_1 () {}
}

class Child_2 extends Mother {
  Child_2 () {}
}

Answers

  • the rhs of the instanceof needs to be known at compile time, you can't use a variable for it.

    in fact, processing 3 gives me a compile error on that line.

  • besides

    c = new Class[c.length -1] ;
    return c ;
    

    this is retuning a new array full of nulls.

    i have no idea what you are trying to do. but you might be able to use getCanonicalName and String.compare.

  • nop I need to put the class here :) to create a generic method for the future and unknow subclasses who can be use this method !

  • edited July 2016 Answer ✓

    The operator instanceof only accepts class names known at compile time.
    Those names can't come from something calculated at runtime.

    However we can replace instanceof w/ Class::isAssignableFrom() method:
    http://docs.Oracle.com/javase/8/docs/api/java/lang/Class.html#isAssignableFrom-java.lang.Class-

    Dunno why you'd need such convoluted & slow checks, but here's the "fix": :-\"

    // forum.Processing.org/two/discussion/17645/check-sub-class-with-instanceof
    // GoToLoop (2016-Jul-25)
    
    void setup() {
      Child1 c = new Child1();
      Class<?>[] m = nestedClasses(this);
    
      printArray(m);
      println();
    
      for (int i = 0; i < m.length; ++i) {
        if (c instanceof Mother)
          println(i, c, "is an instance of", Mother.class);
    
        if (m[i].isAssignableFrom(c.getClass()))
          println(i, m[i], "can be assigned to", c);
    
        println();
      }
    
      exit();
    }
    
    static Class<?>[] nestedClasses(final PApplet parent) {
      return parent.getClass().getDeclaredClasses();
    }
    
    static class Mother {
    }
    
    static class Child1 extends Mother {
    }
    
    static class Child2 extends Mother {
    }
    
  • thx @gotoloop, It's exactly what I need. Why you say is slow check ?

  • edited July 2016

    Reflection operations are slower than direct access. That's all. :P
    And we should avoid reflection when direct access is within our grasp. L-)

  • obviously...but I want use this method for a specific thing, and lock it if I don't need to don't slow my program !

  • It would be useful I if you gave more info about what you are trying to achieve, not in an abstract way but a concrete description. I suspect that there will be a simple way to do what you want without resorting to the tortuous code you have posted.

  • @quark sur is complicated thing. I work on ecosystem project, with different creatures with a lot of common method, and I don't want write a same method for each sub-class of creature. I post the project link tomorrow on my github.

  • Then instead of an interface create an abstract class for the parent class and put all the common methods in there.

  • but my problem is : the methods are outside the class. And I must check if the method is usable by the sub-class or not.

  • edited July 2016

    Haven't I already showed you an example about having some kinda ABSENCE value to indicate some method is invalid for that particular class? 8-X

    https://forum.Processing.org/two/discussion/17617/catch-variable-from-class-object-when-this-one-is-a-instanceof#Item_8

    So instead of instanceof we check whether the return value isn't ABSENCE. *-:)

  • I will try to mix all my question and your reponses -@quark and you about classes, before my future post. But i'm not an class expert, but with your light I can be better :)

  • edited July 2016

    Some ideas about abstract classes. A good alternative or complement to interfaces:
    https://forum.Processing.org/two/discussion/13616/inheritance-in-a-class-with-an-array-loop

  • You state earlier that GoToLoop's solution using isAssignable(...) does exactly what you want. His comment about not using reflection when an alternative is available is also true but the fact that it is slightly slower than a good OO alternative should NOT stop you using.

    It is extremely unlikely you will notice any difference in your application when using reflection.

    My G4P library uses reflection extensively and no one has complained about it has slowed their application. :)

  • edited July 2016

    On this link the reason why I need to use instanceof' and find a method to put the name of the sub-class with isAssignableFrom(c.getClass() https://github.com/StanLepunK/Digital-Life-Processing/tree/master/ECO_SYSTEM the point is ont the tab M_agent between the line 32 and 55. The code that's work but I want make something smalles and without name the class.

  • the lines in question

    void info_agent(ArrayList<Agent> list) {
      for(Agent a : list) {
        if(a instanceof Herbivore) {
          Herbivore h = (Herbivore) a ;
          h.info(h.get_fill(), SIZE_TEXT_INFO) ;
        }
        if(a instanceof Carnivore) {
          Carnivore c = (Carnivore) a ;
          c.info(c.get_fill(), SIZE_TEXT_INFO) ;
        }
        if(a instanceof Bacterium) {
          Bacterium b = (Bacterium) a ;
          b.info(b.get_fill(), SIZE_TEXT_INFO) ;
        }
        if(a instanceof Flora) {
          Flora f = (Flora) a ;
          f.info(f.get_fill(), SIZE_TEXT_INFO) ;
        }
        if(a instanceof Dead) {
          Dead d = (Dead) a ;
          d.info(d.get_fill(), SIZE_TEXT_INFO) ;
        }
      }
    }
    

    if Herbivore, Carnivore, Bacterium, Flora and Dead all implement an interface hasInfo and that is defined as having two methods info() and get_fill() then there'd be no need for any of the instanceof stuff.

  • in fact if you marked Agent as implementing hasInfo then that'd be enough.

  • oh, Agent is already an interface. you can just add the method signatures to that.

    that way you know all the list are Agents so you know they all have info() and get_fill() so it's safe to just a.info(a.get_fill(), SIZE_TEXT_INFO);

  • there's a little problem will be coming, because info()is nor from the interfaceand nor from the abstract classbut from the sub class so I must instanceofit

  • edited July 2016

    If the method info() is declared in the interface or abstract class then you don't need to use instanceof because at runtime Java will look at the object and select the correct info method for the object's class. This is called polymorphism a important concept in object orientation.

  • edited July 2016

    nor from the abstract classbut from the sub class

    it would be a lot easier on us if you gave the actual names of the classes here. your code is, er, unorthodox.

    i have a null pointer exception when i try and run this. it's in float_to_String_3() when the input is 25.0. i have no idea where that value is coming from.

  • edited July 2016

    @quark I must make few tricky stuff but that's work now like you write

    void info_agent(ArrayList<Agent> list) {
      for(Agent a : list) {
        a.info(a.get_fill(), SIZE_TEXT_INFO) ;
      }
    }
    

    but I must write my method with a fake methods in the abstract class, because info()call two methods specific from the subclass.

      void info(Vec4 colour, int size_text) {
          info_visual(colour_info(colour, satiate, pregnant, fertility)) ;
          info_text(colour_info(colour, satiate, pregnant, fertility), size_text) ;
      }
      /**
      fake
      */
      void info_visual(Vec4 colour) {
    
      }
    
      void info_text(Vec4 colour, int size) {
    
      }
    
  • @koogs I don't undestand why you have a nullpointer exception, very weird because that's work perfectly at home. I suppose the 25.0is from the genetic part, because I need toString the value to write the gene agent. I reload the last version on github, try it, may be the bug is dissapear :)

  • ArrayIndexOutOfBoundsException: index 1

    String float_to_String_3(float data) {
      ...
      String [] temp = split(float_string_value, ",") ;
      float_string_value = temp[0] +"." + temp[1] ;
    

    float_string_value is 25.000 - it might be a locale thing because you're splitting on , and i have no comma.

  • edited July 2016

    to wait the good solution, I updated the method float_to_String to check if there is dot in the String who be created :) Now I think that's work fine for you. I'm going work deep on the DecimalFormatSymbols in the future.

Sign In or Register to comment.