Can this be made a class variable?

Okay, on with my little project...

In the following clipped piece of code, I would like to make the HashMap a class variable, because the values stored in it never change and there's no reason for each instance to have its own.

class Cement {

  private HashMap<String, Pigment> chart;

  Cement() {
    chart = new HashMap<String, Pigment>();
    chart.put("GN", new Pigment("GN", 137));
    chart.put("2R", new Pigment("2R", 143));
    chart.put("8G", new Pigment("8G", 255));
  }
}

class Pigment {

  private String name; // name
  private int v; // value

  Pigment(String t_name, int t_v) {
    name = t_name;
    v = t_v;
  }
}

I've tried with a static initializer static{}

class Cement {

  private static HashMap<String, Pigment> chart;

  static {
    chart = new HashMap<String, Pigment>();
    chart.put("GN", new Pigment("GN", 137));
    chart.put("2R", new Pigment("2R", 143));
    chart.put("8G", new Pigment("8G", 255));
  }

  Cement() {
  }
}

class Pigment {

  private String name; // name
  private int v; // value

  Pigment(String t_name, int t_v) {
    name = t_name;
    v = t_v;
  }
}

I get error:

Cannot define static initializer in inner type xxx.xxx

Then I found information about nested classes and the fact you need an enclosing class to use static... I'm a bit lost here. --> Is it possible to make this HashMap a class variable? --> I didn't know my class Pigment was nested... is it?

Tagged:

Answers

  • I didn't know my class Pigment was nested... is it?

    yes. the preprocessor throws a class around your entire sketch making all your classes inner classes.

    the way around this, iirc, is to move the class to a new file with a .java extension.

  • 1st of all, some essential introduction to the subject: :-B

    Processing's pre-processor gathers all ".pde" tabs together and wraps 'em all up as 1 top class!
    Therefore our own classes & interfaces there become nested to that PApplet "sketch mega class"!

    There are 3 types of nested classes:

    1. static
    2. inner (non-static)
    3. anonymous (non-static too)

    Conventionally in the Java world, anonymous class instantiation is the only type considered by programmers!
    Inner classes are mostly a Processing thing aFaIK. And static nested classes are even a rarer sight anywhere!

    I would like to make the HashMap a class variable, because the values stored in it never change
    and there's no reason for each instance to have its own.

    I believe you meant to have around a shareable & somewhat "immutable" data container, right?
    It's a wise choice avoid wasting RAM unnecessarily btW. =D> However you've got some obstacles ahead! :-SS

    I've tried with a static initializer static {}. Cannot define static initializer in inner type xxx.xxx

    Neither an inner class nor an anonymous instance can have anything static within them.
    W/ notorious rule exception for primitive & String constant fields w/ known compile-time values! L-)

    Also, static methods & initializer blocks are restricted to access other static members only!
    Only non-static methods & initializer blocks can access both static & non-static members!

    Next post I'm gonna discuss some solutions for that seeming impasse! O:-)

  • edited August 2014

    The way around this, iirc, is to move the class to a new file with a .java extension.

    Let's consider @koogs' proposal:

    A separate ".java" tab would allow us to have top classes in it.
    A regular top class is the opposite of a nested 1. And can have both static & non-static members! \m/
    It is indeed the logical solution for Java's point-of-view. However, not so much for Processing's! Here's why: @-)

    • Processing's pre-processor won't touch non-".pde" files at all.
    • Hence we gotta know the nuts & bolts about Processing's syntax differences in relation to Java's!
    • Then we gotta make the conversion ourselves when needed!
    • We can't access non-static members from Processing's API and its canvas w/o its PApplet reference!
    • Thus we gotta type that reference every time we need to call something as simple as a rect() method!
    • It's unpleasant & ugly for a Processing programmer to do so! :P

    In short, we should stick w/ nested classes in order to preserve some Processing familiarity.
    Coming next round some workarounds to access static members inside non-static classes! o->

  • I disagree with GoToLoop's conclusion. .java tabs are OK, in some cases.
    The class shown above doesn't use any Processing specific features, so it is a perfect candidate to put in a .java file.

  • edited August 2014

    I disagree with @GoToLoop's conclusion.

    It's self-evident ".java" tabs are outside Processing's approach of turning everything into a PApplet class! :O)
    That was a smart move, since we can directly access the whole Processing's API w/o an explicitly reference!
    That is exactly what made a Java-based Processing palatable for its main target audience! (*)

    @Moxl is looking for some way to have static fields in nested classes. Which is by itself an advanced topic!

    Since nested classes are virtually unknown in the Java world, few folks know static members can have issues!
    Even fewer know that regular top classes are implicitly static.
    And that's why we can freely have both static & non-static members in them!

    So how can we include static members in an inner class after all? The solution is as simple as making an inner class inherit static members from another static class or interface! And here's a recent case: *-:)

    In this thread: http://forum.processing.org/two/discussion/6838/1d-array-affecting-2d-array
    Hosted online: http://studio.processingtogether.com/sp/pad/export/ro.91FXxn8BG2fPL/latest

    There's a class there called Box that includes 2 fields for defining its rect()'s dimensions.
    Their values depend on non-static canvas' width & height. So I couldn't declare them static final!

    Problem is that even though all Box objects would have the exact same dimensions, 2 unnecessary dx & dy fields would be instantiated for each 1 in the process! While 1 shareable pair would be just enough!

    But since Box is an inner class (non-static), we can't implement static members in it.
    Unless they're primitive or String constants as I've already mentioned before!

    In order to fix that, I've implemented a separate static nested class called BoxData,
    placed those dx & dy as static fields there, and made Box extend it: \m/

    static abstract class BoxData {
      static final int STROKE = -1, WEIGHT = 1, GAP = 5;
      static int dx, dy;
    }
    
    final class Box extends BoxData {
      final short x, y;
    
      // ...
    
      void fillBox(color c) {
        fill(c, 100, 100);
        rect(x, y, dx, dy);
      }
    
      // ...
    }
    

    Now Box objects can access dx & dy fields, while only 1 copy of them exists. Problem solved! <):)
    No need for complicated separate ".java" tabs at all! :))

  • edited August 2014

    Having a look at your 2 classes: Cement & Pigment, they don't make much sense.

    Why having the same String key in the HashMap repeated as a field for the Pigment class?
    chart.put("GN", new Pigment("GN", 137));

    It seems like you're trying to make Pigment imitate a Map data container somehow!? :-??
    I'll consider that you merely wanted to inherit a HashMap object referenced by a static field, right?

    Following the same static nested class technique I did before, I've made a static abstract class called Chart
    in order to contain only 1 HashMap instance. And a non-static inner class called Pigment to extend Chart's members:

    // forum.processing.org/two/discussion/6863/
    // can-this-be-made-a-class-variable
    
    import java.util.Map;
    
    static abstract class Chart {
      static final Map<String, Integer> charts = new HashMap();
    
      static {
        charts.put("GN", 137);
        charts.put("2R", 143);
        charts.put("8G", 255);
      }
    }
    
    final class Pigment extends Chart {
    }
    
    void setup() {
      println(Pigment.charts);
      exit();
    }
    

    And an alternative option using an IntDict inside an interface:

    // forum.processing.org/two/discussion/6863/
    // can-this-be-made-a-class-variable
    
    interface Chart {
      IntDict charts = new IntDict
        (new String[] {
        "GN", "2R", "8G"
      }
      , new int[] {
        137, 143, 255
      }
      );
    }
    
    final class Pigment implements Chart {
    }
    
    void setup() {
      println(Pigment.charts);
      exit();
    }
    
  • edited August 2014

    In order to fix that, I've implemented a separate static nested class called BoxData, placed those dx & dy as static fields there, and made Box extend it

    Yes! Thanks @GoToLoop, that's what I'll use, I guess. But then, in your first BoxData example, how is it that declaring BoxData as abstact make it possible to declare class variables in class Box?

    Why having the same String key in the HashMap repeated as a field to the Pigment class?

    Well observed, I thought about that after posting. Actually, the Pigment object contains more instance variables, which I just omitted for the snippet. Probably not a winning formatting choice for the post, too...

  • edited August 2014 Answer ✓

    ... how is it that declaring BoxData as abstract...

    It's completely unrelated. It just needs to be static! You can freely remove that if you wish so. ;))
    Just declared it abstract as a hint that it's not supposed to be instantiated. Rather inherited from another class!

    ... make it possible to declare class variables in class Box?

    Both dx & dy static fields weren't declared inside inner class Box; rather in static class BoxData.
    Inner class Box merely inherited from static nested class BoxData's members! :-B

  • Hah! Is this a nice trick or what?! Thanks.

    PS: unrelated, maybe someone could PM, but how do I include emoticons in posts? Do I need to write HTML?

  • edited August 2014

    There's a smiley button at the far top right in this very typing box! <:-P

  • edited August 2014

    Oh right. I had this script blocker running, maybe that's the reason I couldn't see the button... :)

  • I believe you meant to have around a shareable & somewhat "immutable" data container, right?

    By the way, yes, you totally got what I meant. Sorry for lacking vocabulary...

Sign In or Register to comment.