Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Easy Learn Java: Programming Articles, Examples and Tips - Page 188


Previous 1060 Stories (530 Pages, 2 Per Page) Next

Story By Dr. Kabutz: Insane Strings

Go to all tips in Story by Dr. Kabutz
2001-03-15 The Java Specialists' Newsletter [Issue 013b] - Follow-up
Author: Dr. Heinz M. Kabutz

You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile


Hi again,

Imagine my horror this morning when I tried to run the code from last nights newsletter and discovered that it generated an exception! On frantic searching I figured that the JBuilder 3.0 compiler produces a different result to the SUN JDK 1.3 compiler. I had only run the program from within JBuilder, so I got quite a surprise that it did not work in SUN. The reason I'm blaming the compiler is because when I ran the class files generated by JBuilder 3.0 with the JDK 1.3 VM it works perfectly.

The problem is that if you call out.defaultWriteObject(), the two compilers have different ideas of which object you are calling this from, because you are inside an inner class. The SUN compiler thinks you are calling it from ComponentSerializer and that is not serializable.

The solution is quite simple, just move the ComponentEncapsulator class out of the ComponentSerializer class and it should work with the JDK 1.3 compiler.

We thus end up with ComponentSerializer:

//: ComponentSerializer.java
import java.io.*;
import java.awt.*;
public class ComponentSerializer {
  public void write(Component comp, OutputStream out)
      throws IOException {
    System.out.println("writing " + comp);
    ObjectOutputStream oout = new ObjectOutputStream(out);
    oout.writeObject(new ComponentEncapsulator(comp));
    oout.reset();
    oout.flush();
  }
  public Component read(InputStream in)
      throws IOException, ClassNotFoundException {
    System.out.println("reading component");
    ObjectInputStream oin = new ObjectInputStream(in);
    ComponentEncapsulator enc =
      (ComponentEncapsulator)oin.readObject();
    return enc.getComponent();
  }
}
 
2001-03-21 The Java Specialists' Newsletter [Issue 014] - Insane Strings
Author: Dr. Heinz M. Kabutz
You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile

Welcome to the 14th issue of "The Java(tm) Specialists' Newsletter", where we look at things that other newsletters would not dare to mention. Please please use the ideas presented in this newsletter with caution, they can really mess up a project if used (incorrectly). A lot of them are educational rather than practical so that we can understand Java better. This is true especially for this newsletter, in which we mutate Strings.

Thanks if you forwarded last week's newsletter to some of your colleagues and friends, I got a few subscriptions as a result of referrals. The membership has been growing steadily since I started this newsletter in November 2000. It has now broken through the 400 barrier and I'm thinking of moving it to a proper list server before reaching 500. My main concern is that if it is a free list server it might start sending you spam, which I really would not like. Any suggestions of free list servers that do not generate spam would be most welcome. My current preference is for Topica - which I will choose unless I hear from you.

Playing with your sanity - Strings

Have a look at the following code:

public class MindWarp {
  public static void main(String[] args) {
    System.out.println(
      "Romeo, Romeo, wherefore art thou oh Romero?");
  }
  private static final String OH_ROMEO =
    "Romeo, Romeo, wherefore art thou oh Romero?";
  private static final Warper warper = new Warper();
}
 

If we are told that the class Warper does not produce any visible output when you construct it, what is the output of this program? The most correct answer is, "you don't know, depends on what Warper does". Now THERE's a nice question for the Sun Certified Java Programmer Examination.

In my case, running "java MindWarp" produces the following output

C:> java MindWarp 
Stop this romance nonsense, or I'll be sick

And here is the code for Warper:

import java.lang.reflect.*;

public class Warper {
  private static Field stringValue;
  static {
    // String has a private char [] called "value"
    // if it does not, find the char [] and assign it to value
    try {
      stringValue = String.class.getDeclaredField("value");
    } catch(NoSuchFieldException ex) {
      // safety net in case we are running on a VM with a
      // different name for the char array.
      Field[] all = String.class.getDeclaredFields();
      for (int i=0; stringValue == null && iif (all[i].getType().equals(char[].class)) {
          stringValue = all[i];
        }
      }
    }
    if (stringValue != null) {
      stringValue.setAccessible(true); // make field public
    }
  }
  public Warper() {
    try {
      stringValue.set(
        "Romeo, Romeo, wherefore art thou oh Romero?",
        "Stop this romance nonsense, or I'll be sick".
          toCharArray());
      stringValue.set("hi there", "cheers !".toCharArray());
    } catch(IllegalAccessException ex) {} // shhh
  }
}

How is this possible? How can String manipulation in a completely different part of the program affect our class MindWarp?

To understand that, we have to look under the hood of Java. In the language specification it says in §3.10.5:

"Each string literal is a reference (§4.3) to an instance (§4.3.1, §12.5) of class String (§4.3.3). String objects have a constant value. String literals-or, more generally, strings that are the values of constant expressions (§15.2Cool-are "interned" so as to share unique instances, using the method String.intern."

The usefulness of this is quite obvious, we will use less memory if we have two Strings which are equivalent pointing at the same object. We can also manually intern Strings by calling the intern() method.

The language spec goes a bit further:

  1. Literal strings within the same class (§Cool in the same package (§7) represent references to the same String object (§4.3.1).
  2. Literal strings within different classes in the same package represent references to the same String object.
  3. Literal strings within different classes in different packages likewise represent references to the same String object.
  4. Strings computed by constant expressions (§15.2Cool are computed at compile time and then treated as if they were literals.
  5. Strings computed at run time are newly created and therefore distinct.
  6. The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

This means that if a class in another package "fiddles" with an interned String, it can cause havoc in your program. Is this a good thing? (You don't need to answer Wink

Consider this example

public class StringEquals {
public static void main(String[] args) {
  System.out.println("hi there".equals("cheers !"));
}
private static final String greeting = "hi there";
private static final Warper warper = new Warper();
}

Running this against the Warper produces a result of true, which is really weird, and in my opinion, quite mind-bending. Hey, you can SEE the values there right in front of you and they are clearly NOT equal!

BTW, for simplicity, the Strings in my examples are exactly the same length, but you can change the length quite easily as well.

Last example concerns the HashCode of String, which is now cached for performance reasons mentioned in "Java Idiom and Performance Guide", ISBN 0130142603. (Just for the record, I was never and am still not convinced that caching the String hash code in a wrapper object is a good idea, but caching it in String itself is almost acceptable, considering String literals.)

public class CachingHashcode {
  public static void main(String[] args) {
    java.util.Map map = new java.util.HashMap();
    map.put("hi there", "You found the value");
    new Warper();
    System.out.println(map.get("hi there"));
    System.out.println(map);
  }
  private static final String greeting = "hi there";
}

The output under JDK 1.3 is:

You found the value
{cheers !=You found the value}

Under JDK 1.2 it is

null
{cheers !=You found the value}

This is because in the JDK 1.3 SUN is caching the hash code so if it once calculated, it doesn't get recalculated, so if the value field changes, the hashcode stays the same.

Imagine trying to debug this program where SOMEWHERE, one of your hackers has done a "workaround" by modifying a String literal. The thought scares me.

There is of course a small keyword that would have stopped this problem, namely "final". I got into the habit a few months ago to make all my data members final where possible, and it has paid off more than once. Surprisingly, the char array in String is not final.

Consider the following example code:

public class Bla {
  private char[] c1 = "hello".toCharArray();
  private final char[] c2 = "bye".toCharArray();
  public String toString() {
    return c1 + ", " + c2;
  }
}

import java.lang.reflect.*;

public class BlaTest {
  private static Field c1;
  private static Field c2;
  static {
    try {
      c1 = Bla.class.getDeclaredField("c1");
      c1.setAccessible(true);
      c2 = Bla.class.getDeclaredField("c2");
      c2.setAccessible(true);
    } catch(NoSuchFieldException ex) { }
  }
  public static void main(String[] args) {
    Bla bla = new Bla();
    try {
      c1.set(bla, "mutatedc1".toCharArray());
      c2.set(bla, "mutatedc2".toCharArray());
    } catch(IllegalAccessException ex) {
      ex.printStackTrace();
    }
    System.out.println(bla);
  }
}

When I run my program, I can quite happily change c1, but when I try to change c2 I get an exception. String has no reason for value to be non-final, so it should be final. If you have contacts at SUN, please forward them this newsletter and ask them to make value final. It might stop some nasty Java viruses from completely messing up the JVM.

Until next week, and please remember to forward this newsletter and send me your comments.

Heinz


Copyright 2000-2003 Maximum Solutions, South Africa
Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.

10082 bytes more | 72 comments | Printer Friendly Page  Send to a Friend | Story By Dr. Kabutz | Score: 0
Posted by jalex on Monday, March 22, 2004 (00:00:00) (4276 reads)

The Java Lesson 14: Creating and calling custom class methods

Go to all tips in Java Lessons by Jon Huhtala
All Java Lessons contents page | Java Lesson 1 | Java Lesson 2 | Java Lesson 3 | Java Lesson 4 | Java Lesson 5 | Java Lesson 6 | Java Lesson 7 | Java Lesson 8 | Java Lesson 9 | Java Lesson 10 | Java Lesson 11 | Java Lesson 12 | Java Lesson 13 | Java Lesson 14 | Java Lesson 15 | Java Lesson 16 | Java Lesson 17 | Java Lesson 18 | Java Lesson 19 | Java Lesson 20 | Java Lesson 21 | Java Lesson 22 | Java Lesson 23 | Java Lesson 24 | Java Lesson 25 | Java Lesson 26 | Java Lesson 27 | Java Lesson 28 | Java Lesson 29 | Java Lesson 30 | Java Lesson 31 | Java Lesson 32 | Java Lesson 33 | Java Lesson 34 | Java Lesson 35 | Java Lesson 36 | Java Lesson 37 | Java Lesson 38 | Java Lesson 39 | Java Lesson 40 | Java Lesson 41 | Java Lesson 42 | Java Lesson 43 | Java Lesson 44 | Java Lesson 45 | Java Lesson 46

The Java Lesson 14

Creating and calling custom class methods

Custom class methods

  • Can be defined within any class but not within another method. Methods can not be nested.

  • Are associated with the class itself and not with an object of the class. This is indicated by the use of the static keyword within the method's header. No object must exist to call a class method.

  • Have the general syntax

public static return-type method-name(arguments) {
statements;
}

where:

return-type is the data type of the value to be returned by the method when it completes its processing. This may be any primitive data type (such as boolean, byte, char, etc..) or the keyword void if the method returns nothing to the caller. If the method returns an object reference, a class name may be specified. This will be covered in a later lesson.

method-name is any valid identifier. It should be meaningful and follow Java coding conventions by beginning with a lower case letter.

arguments is a list of local variables whose values are received as parameters from the caller. If the method requires no arguments, nothing is coded within the parenthesis.

statements are one or more statements that define the method's processing. In addition to the local variables received as parameters, other local variables may be declared.

  • May have one or more return statements. If the method header indicates that the method is to return a value, a return statement of the form

return expression;

is required where expression is compatible with the return-type specified in the method header. If the method header indicates that no value is to be returned (void is specified), a null return statement such as

return;

may be coded. Otherwise, processing will automatically end when the closing brace of the method is reached.

  • Receive a copy of values passed from the caller. For security reasons, a class method is never allowed to access the primitive variables of the calling method (objects are a bit different and will be covered later). For example, if a class method is defined with the following header:

public static double extendedPrice(int quantity, double unitPrice)

it expects to receive two parameters. If a calling method has an int variable named qty and a double variable named price, it can call the extendedPrice method with the following expression:

extendedPrice(qty, price)

The caller's values of qty and price will automatically be copied and assigned to the method's local variables named quantity and unitPrice.

When parameters are passed:

  1. The match-up is entirely positional. The first parameter value is copied and assigned to the first local variable declared in the method header, the second parameter value is copied and assigned to the second local variable declared in the method header, etc..

  2. Trying to pass too few or too many parameters will result in a compile error.

  3. Variable names are irrelevant. Even if the same identifier is used in both the calling method and in the class method, they reference different memory areas.

  4. Data types must be compatible and, if necessary, widening conversions are automatically performed. For example, the extendedPrice method could be called with a byte and an int because they can be widened to the expected int and double.

  • Have variables with a limited scope. The memory space of method local variables is automatically garbage collected when the method ends. Only the value returned from the method (if any) is available to the caller.


Creating and calling custom class methods

Custom class methods

  • Can be defined within any class but not within another method. Methods can not be nested.

  • Are associated with the class itself and not with an object of the class. This is indicated by the use of the static keyword within the method's header. No object must exist to call a class method.

  • Have the general syntax

public static return-type method-name(arguments) {
statements;
}

where:

return-type is the data type of the value to be returned by the method when it completes its processing. This may be any primitive data type (such as boolean, byte, char, etc..) or the keyword void if the method returns nothing to the caller. If the method returns an object reference, a class name may be specified. This will be covered in a later lesson.

method-name is any valid identifier. It should be meaningful and follow Java coding conventions by beginning with a lower case letter.

arguments is a list of local variables whose values are received as parameters from the caller. If the method requires no arguments, nothing is coded within the parenthesis.

statements are one or more statements that define the method's processing. In addition to the local variables received as parameters, other local variables may be declared.

  • May have one or more return statements. If the method header indicates that the method is to return a value, a return statement of the form

return expression;

is required where expression is compatible with the return-type specified in the method header. If the method header indicates that no value is to be returned (void is specified), a null return statement such as

return;

may be coded. Otherwise, processing will automatically end when the closing brace of the method is reached.

  • Receive a copy of values passed from the caller. For security reasons, a class method is never allowed to access the primitive variables of the calling method (objects are a bit different and will be covered later). For example, if a class method is defined with the following header:

public static double extendedPrice(int quantity, double unitPrice)

it expects to receive two parameters. If a calling method has an int variable named qty and a double variable named price, it can call the extendedPrice method with the following expression:

extendedPrice(qty, price)

The caller's values of qty and price will automatically be copied and assigned to the method's local variables named quantity and unitPrice.

When parameters are passed:

  1. The match-up is entirely positional. The first parameter value is copied and assigned to the first local variable declared in the method header, the second parameter value is copied and assigned to the second local variable declared in the method header, etc..

  2. Trying to pass too few or too many parameters will result in a compile error.

  3. Variable names are irrelevant. Even if the same identifier is used in both the calling method and in the class method, they reference different memory areas.

  4. Data types must be compatible and, if necessary, widening conversions are automatically performed. For example, the extendedPrice method could be called with a byte and an int because they can be widened to the expected int and double.

  • Have variables with a limited scope. The memory space of method local variables is automatically garbage collected when the method ends. Only the value returned from the method (if any) is available to the caller.

Sample program

The following sample program performs temperature conversions using a class method named convertTemp which is called from the application's main() method:

public class App {
public static void main(String[] args) {

// Variables.

double oldTemp;
char scale;
double newTemp;
char again;

// Loop to process one temperature conversion.

do {

// Get data from the user.

Utility.separator(50, '>');
System.out.print("Enter temperature: ");
oldTemp = Keyboard.readDouble();
System.out.print("Current scale? (C/F): ");
scale = Keyboard.readChar();

// Process the conversion request.

Utility.skip();
switch (scale) {

// Cases for a valid scale.

case 'C':
case 'c':
case 'F':
case 'f':
newTemp = convertTemp(oldTemp, scale);
System.out.println(" Converted temperature: " +
Utility.fixedFormat(newTemp, 2));
break;

// Default case for an invalid scale.

default:
System.out.println(" Invalid scale");
break;
}

// Ask if they want to do another and repeat as requested.

Utility.skip();
System.out.print("Again? (Y/N): ");
again = Keyboard.readChar();
} while (again == 'Y' || again == 'y');
}

// Class method to convert a temperature from either centigrade to
// fahrenheit or fahrenheit to centigrade.

public static double convertTemp(double temperature, char scale) {

// If the scale is centigrade, convert the temperature to
// fahrenheit. Otherwise, convert it to centigrade.

if (scale == 'C' || scale == 'c') {
return ((9 * temperature) / 5) + 32;
}
else {
return (5 * (temperature -32)) / 9;
}
}
}

Notes:

  1. The convertTemp() method expects to receive two parameters. The first must be a double (or able to be widened to a double) that represents the temperature to be converted. The second must be a char that represents the scale of the temperature to be converted.

  2. Because the convertTemp() method is defined within the same class as the main() method, it can be called without specifying its class name. Alternatively, App.convertTemp() could have been called.

  3. The convertTemp() method returns a double so it can be called anywhere a double makes sense. That is why it can be assigned to the double variable newTemp.

  4. Because convertTemp() is public, it may be called from any other class. That means no one else in the history of mankind will ever have to write another temperature conversion method as long as they can call App.convertTemp().

Lab exercise for Ferris students

E-mail your answers to this assignment no later than the due date listed in the class schedule.

Review questions

  1. Which one statement is true about the application shown below? The line numbers are for reference purposes only.

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
int length = 5;
int width = 3;
System.out.println("Area is " + area(length, width));
}
public static double area(double len, double wid) {
return len * wid;
}
}
  1. a compile error will occur at line 5

  2. a compile error will occur at line 7

  3. a compile error will occur at line 8

  4. the program will compile but an error will occur at run time

  5. the program will compile and run to display "Area is 15.0"

  1. Which one statement is true about the application shown below? The line numbers are for reference purposes only.

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
int hours = 5;
double rate = 7.25;
System.out.println("Gross pay: " + grossPay());
}
public static double grossPay() {
return hours * rate;
}
}
  1. a compile error will occur at line 5

  2. a compile error will occur at line 7

  3. a compile error will occur at line 8

  4. the program will compile but an error will occur at run time

  5. the program will compile and run to display "Gross pay: 36.25"

  1. Which one statement is true about the application shown below? The line numbers are for reference purposes only.

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
int hours = 5;
double rate = 7.25;
System.out.println("Gross pay: " + grossPay(rate, hours));
}
public static double grossPay(int hours, double rate) {
return hours * rate;
}
}
  1. a compile error will occur at line 5

  2. a compile error will occur at line 7

  3. a compile error will occur at line 8

  4. the program will compile but an error will occur at run time

  5. the program will compile and run to display "Gross pay: 36.25"

  1. Which one statement is true about the application shown below? The line numbers are for reference purposes only.

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
int hours = 5;
double rate = 7.25;
System.out.println("Gross pay: " + grossPay(hours, rate));
}
public static double grossPay(int hours, double rate) {
double gross = hours * rate;
}
}
  1. a compile error will occur at line 5

  2. a compile error will occur at line 8

  3. a compile error will occur at line 9

  4. the program will compile but an error will occur at run time

  5. the program will compile and run to display "Gross pay: 36.25"


18287 bytes more | 4 comments | Printer Friendly Page  Send to a Friend | Score: 5
Posted by jalex on Saturday, March 20, 2004 (00:00:00) (16918 reads)

Previous 1060 Stories (530 Pages, 2 Per Page) Next

530| 529| 528| 527| 526| 525| 524| 523| 522| 521| 520| 519| 518| 517| 516| 515| 514| 513| 512| 511| 510| 509| 508| 507| 506| 505| 504| 503| 502| 501| 500| 499| 498| 497| 496| 495| 494| 493| 492| 491| 490| 489| 488| 487| 486| 485| 484| 483| 482| 481| 480| 479| 478| 477| 476| 475| 474| 473| 472| 471| 470| 469| 468| 467| 466| 465| 464| 463| 462| 461| 460| 459| 458| 457| 456| 455| 454| 453| 452| 451| 450| 449| 448| 447| 446| 445| 444| 443| 442| 441| 440| 439| 438| 437| 436| 435| 434| 433| 432| 431| 430| 429| 428| 427| 426| 425| 424| 423| 422| 421| 420| 419| 418| 417| 416| 415| 414| 413| 412| 411| 410| 409| 408| 407| 406| 405| 404| 403| 402| 401| 400| 399| 398| 397| 396| 395| 394| 393| 392| 391| 390| 389| 388| 387| 386| 385| 384| 383| 382| 381| 380| 379| 378| 377| 376| 375| 374| 373| 372| 371| 370| 369| 368| 367| 366| 365| 364| 363| 362| 361| 360| 359| 358| 357| 356| 355| 354| 353| 352| 351| 350| 349| 348| 347| 346| 345| 344| 343| 342| 341| 340| 339| 338| 337| 336| 335| 334| 333| 332| 331| 330| 329| 328| 327| 326| 325| 324| 323| 322| 321| 320| 319| 318| 317| 316| 315| 314| 313| 312| 311| 310| 309| 308| 307| 306| 305| 304| 303| 302| 301| 300| 299| 298| 297| 296| 295| 294| 293| 292| 291| 290| 289| 288| 287| 286| 285| 284| 283| 282| 281| 280| 279| 278| 277| 276| 275| 274| 273| 272| 271| 270| 269| 268| 267| 266| 265| 264| 263| 262| 261| 260| 259| 258| 257| 256| 255| 254| 253| 252| 251| 250| 249| 248| 247| 246| 245| 244| 243| 242| 241| 240| 239| 238| 237| 236| 235| 234| 233| 232| 231| 230| 229| 228| 227| 226| 225| 224| 223| 222| 221| 220| 219| 218| 217| 216| 215| 214| 213| 212| 211| 210| 209| 208| 207| 206| 205| 204| 203| 202| 201| 200| 199| 198| 197| 196| 195| 194| 193| 192| 191| 190| 189|
188
| 187| 186| 185| 184| 183| 182| 181| 180| 179| 178| 177| 176| 175| 174| 173| 172| 171| 170| 169| 168| 167| 166| 165| 164| 163| 162| 161| 160| 159| 158| 157| 156| 155| 154| 153| 152| 151| 150| 149| 148| 147| 146| 145| 144| 143| 142| 141| 140| 139| 138| 137| 136| 135| 134| 133| 132| 131| 130| 129| 128| 127| 126| 125| 124| 123| 122| 121| 120| 119| 118| 117| 116| 115| 114| 113| 112| 111| 110| 109| 108| 107| 106| 105| 104| 103| 102| 101| 100| 99| 98| 97| 96| 95| 94| 93| 92| 91| 90| 89| 88| 87| 86| 85| 84| 83| 82| 81| 80| 79| 78| 77| 76| 75| 74| 73| 72| 71| 70| 69| 68| 67| 66| 65| 64| 63| 62| 61| 60| 59| 58| 57| 56| 55| 54| 53| 52| 51| 50| 49| 48| 47| 46| 45| 44| 43| 42| 41| 40| 39| 38| 37| 36| 35| 34| 33| 32| 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1|


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy