Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Save the whales
Aug 31, 2004

by T. Finn
I have a question about traversing a class hierarchy. Let's say I have these classes:

code:
abstract class ExtendableThing
{
  String getDescription();

  String getAggregateDescription()
  {
    //???
  }
}

class ColoredThing extends ExtendableThing
{
  String getDescription()
  {
    return "colored";
  }
}

class BlueThing extends ColoredThing
{
  String getDescription()
  {
    return "blue";
  }
}

class ShinyBlueThing extends BlueThing
{
  String getDescription()
  {
    return "shiny";
  }
}
What do I put in the "getAggregateDescription" method of ExtendableThing to make it behave like this?

code:
ShinyBlueThing foo = new ShinyBlueThing();

//prints out "shiny, blue, colored"
System.out.println(foo.getAggregateDescription());

//prints out "blue, colored"
System.out.println(((BlueThing)foo).getAggregateDescription());

//prints out "colored"
System.out.println(((ColoredThing)foo).getAggregateDescription());

//prints out ""
System.out.println(((ExtendableThing)foo).getAggregateDescription());

Adbot
ADBOT LOVES YOU

Save the whales
Aug 31, 2004

by T. Finn

Twitchy posted:

You might want to read up on downcasting objects, because at the moment System.Out.Println statements will throw a ClassCastException. Maybe someone else who has a way with words will try and explain why (if not, read up on polymorphism).

I don't see why a ClassCastException would get thrown. foo is a BlueThing, a ColoredThing, and an ExtendableThing so I don't see a problem there.

edit: I'm starting to think this isn't possible because getDescription is overwritten by each subclass. drat it.

Save the whales fucked around with this message at 22:43 on Apr 24, 2008

Save the whales
Aug 31, 2004

by T. Finn
I was hoping that I could avoid having to put the method in each subclass. This code is supposed to go in a shared library at my company and I want to make it really easy to use. So, when my coworkers are making a new kind of ExtendableThing in their projects, all they have to do is make sure it extends ExtendableThing and it works magically. If it were only one method ("getAggregateDescription") then I might have been able to deal with that, but the problem is that there are many methods that need to use a similar strategy (going up the class hierarchy).

This is what I have so far, but it's not working like I expected (it appears to cause infinite recursion):

code:
public String getAggregateDescription()
{
  if (getClass() == ExtendableThing.class)
  {
    return "";
  }
    
  StringBuilder sb = new StringBuilder();
  sb.append(getDescription());
    
  try
  {
    String superAggregateDescription = getClass().getSuperclass()
        .getMethod("getAggregateDescription").invoke(
            this, new Object[] {}).toString();

    if (superAggregateDescription != null && superAggregateDescription.length() > 0)
    {
      sb.append(", ");
      sb.append(superAggregateDescription);
    }
  }
  catch (IllegalAccessException e)
  {
    //do nothing
  }
  catch (InvocationTargetException e)
  {
    //do nothing
  }
  catch (NoSuchMethodException e)
  {
    //do nothing
  }
  catch (NullPointerException e)
  {
    //do nothing
  }
    
  return sb.toString();
}

Save the whales
Aug 31, 2004

by T. Finn
I think I've got it! At least, this solution appears to work. I avoid the problem of the method being overwritten by declaring new instances of the super classes and abandoning recursion.

code:
public String getAggregateDescription()
{
  StringBuilder sb = new StringBuilder();
  Class c = getClass();
  boolean first = true;
    
  try
  {
    while (c != null)
    {
      int mod = c.getModifiers();
      
      if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
      {
        break;
      }
      
      if (first)
      {
        first = false;
      }
      else 
      {
        sb.append(", ");
      }
      
      Object o = c.getConstructor(new Class[] {}).newInstance(new Object[] {});
      sb.append(c.getMethod("getDescription").invoke(
          o, new Object[] {}));
      c = c.getSuperclass();
    }
  }
  catch (Exception e)
  {
    //do nothing
  }
  
  return sb.toString();
}

Save the whales
Aug 31, 2004

by T. Finn

Twitchy posted:

I actually thought of something like that aswell, whether it's usable depends on how often it'll be called, and any memory restrictions etc, since it's hacked together code. Another option would be to make the getDescription() static, since it looks like the value would be a constant anyway. It would also mean you wouldn't clutter up space with immediately discared objects. Just food for thought.

Yeah, it's not the greatest solution but it fits my specific needs. The "getDescription" method isn't static but it returns a static value. I wish I could make it static but unfortunately that method I'm overwriting wasn't originally written by me. It's in that code base used by my company in all of our projects, and I can't go changing that now. Luckily, it happens that the constructors for these things are extremely cheap (they're empty).

Thanks for your help, Twitchy.

Save the whales
Aug 31, 2004

by T. Finn

Entheogen posted:

Ok, I figured it out. if x1=y1=z1=16 and x2=y2=z2=49 for example it runs in infinite loop because 49-16 / 2 = 16 :(

I know how to solve it now. I had overlapping elements anyway which I shouldn't have.

Bleh! Oh well, I'll post what I saw anyways in case it helps any.

code:
public class Main
{
  public static void main(String[] args)
  {
    subdivide(1, 1, 1, 5, 5, 5);
  }
  
  public static void subdivide(int x1, int y1, int z1, int x2, int y2, int z2)
  {
    System.out.println(x1 + ", " + y1 + ", " + x1 + ", " + x2 + ", " + y2 + ", " + z2);
    if (x2-x1 <= 1 || y2-y1 <= 1 || z2-z1 <= 1)  return; 
    subdivide( (x2 - x1) / 2, (y2 - y1) / 2, (z2 - z1) / 2, x2, y2, z2); 
  }
}
produces...

code:
1, 1, 1, 5, 5, 5
2, 2, 2, 5, 5, 5
1, 1, 1, 5, 5, 5
2, 2, 2, 5, 5, 5
1, 1, 1, 5, 5, 5
2, 2, 2, 5, 5, 5
1, 1, 1, 5, 5, 5
2, 2, 2, 5, 5, 5
1, 1, 1, 5, 5, 5
2, 2, 2, 5, 5, 5
1, 1, 1, 5, 5, 5
...etc

Save the whales
Aug 31, 2004

by T. Finn

Capc posted:

It seems to work, but looks a little sloppy. Is there a better way of writing this? For instance, is there a way to determine the amount of characters in an int without converting it to a string?

If you're talking about the base 10 string you can get the number of characters in an int by dividing it by 10 until it's zero. This seems to work:

code:
public static int sumDigits(int n)
{
  while (n >= 10)
  {
    int sum = 0;
    
    while (n > 0)
    {
      sum += n % 10;
      n /= 10;
    }
    
    n = sum;
  }
  
  return n;
}

Save the whales
Aug 31, 2004

by T. Finn

zootm posted:

Well, I do think there is a world of difference between an empty string and a null string; if there's not, you're probably using a String for something that you shouldn't be.

I do web development and I almost always treat them as the same thing, especially in situations where the string is some HTML snippet that will get printed to the page. For instance, if your string is the inner text of some table cell, you probably don't want "null" to end up in there. Or if your string is the CSS class name of the table cell, you probably want both null and the empty string to have your method generate <td> rather than <td class=""> or worse <td class="null">.

Save the whales
Aug 31, 2004

by T. Finn

Edmond Dantes posted:

I thought about using randomly generated strings of a fixed length, but they need to be different for every distinct result on the original table, and I think checking every newly generated one to see if it hasn't been already used would be a mess. I was then thinking about an alphanumeric "counter"; is there any way of taking a string (let's say "AAAAAAA" for example's sake), and transform it into "AAAAAAB", "AAAAAAC" and so on and so forth?

There is a way to generate unique ID strings.
http://java.sun.com/j2se/1.5.0/docs/api/java/util/UUID.html

code:
String uuid = java.util.UUID.randomUUID().toString();
If I remember correctly it contains letters, numbers, and hyphens. Would that suit your purpose?

Save the whales
Aug 31, 2004

by T. Finn

fletcher posted:

I've got a string with an HTML snippet in it. I need a List of innerHTML for all the table cell elements. A regexp seems like the right tool, I'm just horrible at it. Can anybody help me out?

Like this?

code:
String html = "<table><tr><td><a href=\"#\">foo</a><span>bar</span></td><td><div>baz</div></td></tr></table>";
java.util.regex.Matcher m = java.util.regex.Pattern.compile("(?<=<td>).*?(?=</td>)").matcher(html);
while (m.find()) System.out.println(m.group());
I find this serves as a good reference for regex syntax: http://www.regular-expressions.info/reference.html

Adbot
ADBOT LOVES YOU

Save the whales
Aug 31, 2004

by T. Finn

fletcher posted:

Doesn't seem to work when the cell has an attribute: <td onclick="what()"></td>

Oh right it was searching for exactly <td>. Here's another one:

code:
String html = "<table><tr><td onclick=\"what()\"><a href=\"#\">foo</a><span>bar</span></td><td><div>baz</div></td></tr></table>";
java.util.regex.Matcher m = java.util.regex.Pattern.compile("<td.*?>.*?</td>").matcher(html);
while (m.find()) {
  String g = m.group();
  System.out.println(g.substring(g.indexOf('>') + 1, g.lastIndexOf('<')));
}
edit: it probably breaks on nested tables

Save the whales fucked around with this message at 08:46 on Nov 6, 2009

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply