11

I need to create a class with exactly the same methods as java.lang.String.

What is the best way to do this in Java?

I know that I can't extend String class as it is final. I am not looking at solutions where I need to copy the source code of java.lang.String. For example, assume that I need the functionality length() within my custom class named MyString, which has a corresponding 'myLength()` method.

What is the best way to implement myLength()?

I am not looking at various algorithms to find out the length of a string but to reuse String's length() method. Now once I have MyString class ready, I should be able to use it anywhere for my custom manipulations.

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Thunderhashy
  • 5,291
  • 13
  • 43
  • 47
  • 7
    What is the actual problem you are trying to solve? – ZoFreX Jan 15 '10 at 00:27
  • I am trying to find out what design pattern would be best suitable for this kind of problem. – Thunderhashy Jan 15 '10 at 00:34
  • 1
    I always wondered though, why String is final in Java? Sure, it provides all the functionality I ever needed, and never thought of an operation that would require an extension of class String, but still you'll never know what someone might need! – Alex Ntousias Jan 15 '10 at 00:34
  • 2
    @Alex: the choice might have more to do with security than design. Don't ask me to clarify that though, as I think it's just something I may (or may not) have read ;-) – Grundlefleck Jan 15 '10 at 00:48
  • @Alex: The JVM can optimize the bejesus out of `final` classes, since it knows there can never be a subclass. – skaffman Jan 17 '10 at 21:12
  • The source is in the JDK so you copy it, even modify it at your own risk. – Peter Lawrey Jan 17 '10 at 21:23
  • 1
    @Alex, see here: http://stackoverflow.com/questions/2068804/why-string-is-final-in-java – Yishai Jan 18 '10 at 20:51
  • @Yishai Yes, I know :) I created that question :) – Alex Ntousias Jan 18 '10 at 22:56
  • I found several comments/questions on popular final classes like String. I'm looking because I have a handful of valid use-cases where I 'should' extend String; as I may not, I have to use a delegate wrapper. For example I wanted to distinguish a format string from a regular string (at compile time) -- Need FormatString class to wrap String. Might it not be a better solution to have construct that uses "wrap" semantics rather than extend-ing a String. Such that: "FormatString wraps String" ...? – will Jan 27 '15 at 23:44

8 Answers8

12

Going through the various answers here, and the askers updates and clarifications, it appears that what the asker wants is a class that looks, smells and sounds like a String, but is not.

That is they would like to be able to do:

MyString string = "String!!";

This cannot work, since java.lang.String is a final class, and so every "String" that the compiler produces will be a java.lang.String object, since this is not a MyString object they cannot be assigned to each other.

In weakly typed languages you would be able to create such a class, since if a class looks, smells and sounds like a duck, then to all intents and purposes, it is a duck. Java, however, is a strongly typed language, and a duck is only a duck if it happens to be from the Anatidae family of birds.

Paul Wagland
  • 27,756
  • 10
  • 52
  • 74
  • +1 that's true. SO user has asked for a String replica and not a Delegate, where a delegate will still creating a String object. – Punith Raj Feb 02 '15 at 05:51
8

Since final classes cannot be subclassed, create a new class that has a String instance inside and operate on this object.

public class MyString {
  private String s;

  public MyString( String s ) {
    setInternalString( s );
  }

  public int myLength() {
    return getInternalString().length();
  }

  private void setInternalString( String s ) {
    this.s = s;
  }

  private String getInternalString() {
    return this.s == null ? "" : this.s;
  }
}
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
TBH
  • 451
  • 2
  • 9
6

From your question it sounds like the thing you are looking for is simple delegation:

class MyString {

  String delegate; // The actual string you delegate to from your class

  public MyString(String delegate) {
    this.delegate = delegate; // Assign the string that backs your class
  }

  int length() {
    return delegate.length(); // Delegate the method call to the string
  }

  // other methods that delegate to the string field
}
Fabian Steeg
  • 44,988
  • 7
  • 85
  • 112
3

I assume you mean java.lang.String. However, you can't replace String with your own class. You can make another class with the same methods (by copying the source code and changing the package declaration), but you won't be able to pass instances of that class to methods that require a String.

Which brings up an important question: why do you think you want to do this?

erickson
  • 265,237
  • 58
  • 395
  • 493
  • I do not want to create a class just by copying all the methods from String class. This question was asked to me in an interview. – Thunderhashy Jan 15 '10 at 00:33
  • 3
    Maybe it was a trick question, and you were supposed to explain to them why doing this would prevent you from inter-operating with almost ever existing Java API. – erickson Jan 15 '10 at 00:43
  • 1
    Another answer to the interview would be point out that String implements CharSequence and you can create other implementations. Of course, that doesn't help if the APIs that use the ersatz string require a String rather than a CharSequence. – Stephen C Jan 15 '10 at 03:39
3

Proxy design pattern, I guess. It's a stupid question, though (not a reflection on the asker, but on the person that asked him it in a job interview). Possibly the person asking you didn't realise that String is final? Otherwise I can't think why they would even ask.

ZoFreX
  • 8,812
  • 5
  • 31
  • 51
  • 1
    I think the real challenge lies in the fact that the String is final. Otherwise the answer is pretty simple isnt it? Just extend String and you are done with. – Thunderhashy Jan 15 '10 at 00:59
2

Make a new class (it will need a different package, of course, implement the same interface and add all the public methods from the String class (read the javadoc to make sure you got everything).

I have to assume this is homework.

Yishai
  • 90,445
  • 31
  • 189
  • 263
1

You may use the refactoring: Replace inheritance with delegation, which basically is ( as shown in previous answers ) to create an instance variable of the desired type and implement all its methods in the new class and passing the message to them.

Create a field for the superclass, adjust methods to delegate to the superclass, and remove the subclassing.

https://www.refactoring.com/catalog/repInherWithDel.gif

You'll notice this is a lot of typing, that's when a good IDE comes handy.

The following video shows how IntelliJ IDEA 9 does it.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
0

If you just want to override a portion of the String behaviour you could try using a dynamic proxy. Look up java.lang.reflect.Proxy in the API.

Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
BigMikeW
  • 821
  • 5
  • 14
  • The built-in dynamic proxy support only works with interfaces. ASM and other bytecode libraries can work with classes, but I'm not sure about final classes. – erickson Jan 15 '10 at 00:55