funciones - string[] java
Java Strings: "String s=new String(" tonto ");" (23)
Soy un chico C ++ aprendiendo Java. Estoy leyendo Effective Java y algo me confundió. Dice nunca escribir código como este:
String s = new String("silly");
Porque crea objetos String
innecesarios. Pero en su lugar debería escribirse así:
String s = "No longer silly";
Ok bien hasta ahora ... Sin embargo, dada esta clase:
public final class CaseInsensitiveString {
private String s;
public CaseInsensitiveString(String s) {
if (s == null) {
throw new NullPointerException();
}
this.s = s;
}
:
:
}
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
¿Por qué está bien la primera afirmación? No debería ser
CaseInsensitiveString cis = "Polish";
¿Cómo hago que
CaseInsensitiveString
comporte comoString
para que la declaración anterior seaCaseInsensitiveString
(con y sin extensión deString
)? ¿Qué tiene String que hace que sea correcto poder pasar un literal como ese? Según mi entender, no hay un concepto de "copia constructor" en Java.
- ¿Cómo hago que CaseInsensitiveString se comporte como String para que la declaración anterior sea correcta (con and w / out extendiendo String)? ¿Qué tiene String que hace que sea bueno poder pasarlo literalmente así? Según tengo entendido, no existe un concepto de "constructor de copia" en Java, ¿verdad?
Ya se ha dicho lo suficiente desde el primer punto. "Polaco" es un literal de cadena y no se puede asignar a la clase CaseInsentiviveString.
Ahora sobre el segundo punto
Aunque no puede crear nuevos literales, puede seguir el primer elemento de ese libro para un enfoque "similar", por lo que las siguientes afirmaciones son verdaderas:
// Lets test the insensitiveness
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
Aquí está el código.
C:/oreyes/samples/java/insensitive>type CaseInsensitiveString.java
import java.util.Map;
import java.util.HashMap;
public final class CaseInsensitiveString {
private static final Map<String,CaseInsensitiveString> innerPool
= new HashMap<String,CaseInsensitiveString>();
private final String s;
// Effective Java Item 1: Consider providing static factory methods instead of constructors
public static CaseInsensitiveString valueOf( String s ) {
if ( s == null ) {
return null;
}
String value = s.toLowerCase();
if ( !CaseInsensitiveString.innerPool.containsKey( value ) ) {
CaseInsensitiveString.innerPool.put( value , new CaseInsensitiveString( value ) );
}
return CaseInsensitiveString.innerPool.get( value );
}
// Class constructor: This creates a new instance each time it is invoked.
public CaseInsensitiveString(String s){
if (s == null) {
throw new NullPointerException();
}
this.s = s.toLowerCase();
}
public boolean equals( Object other ) {
if ( other instanceof CaseInsensitiveString ) {
CaseInsensitiveString otherInstance = ( CaseInsensitiveString ) other;
return this.s.equals( otherInstance.s );
}
return false;
}
public int hashCode(){
return this.s.hashCode();
}
// Pruebe la clase usando la palabra clave "assert"
public static void main( String [] args ) {
// Creating two different objects as in new String("Polish") == new String("Polish") is false
CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish");
CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish");
// references cis1 and cis2 points to differents objects.
// so the following is true
assert cis1 != cis2; // Yes they''re different
assert cis1.equals(cis2); // Yes they''re equals thanks to the equals method
// Now let''s try the valueOf idiom
CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish");
CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish");
// References cis3 and cis4 points to same object.
// so the following is true
assert cis3 == cis4; // Yes they point to the same object
assert cis3.equals(cis4); // and still equals.
// Lets test the insensitiveness
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
// Futhermore
CaseInsensitiveString cis7 = CaseInsensitiveString.valueOf("SomethinG");
CaseInsensitiveString cis8 = CaseInsensitiveString.valueOf("someThing");
assert cis8 == cis5 && cis7 == cis6;
assert cis7.equals(cis5) && cis6.equals(cis8);
}
}
C:/oreyes/samples/java/insensitive>javac CaseInsensitiveString.java
C:/oreyes/samples/java/insensitive>java -ea CaseInsensitiveString
C:/oreyes/samples/java/insensitive>
Es decir, crea un grupo interno de objetos CaseInsensitiveString y devuelve la instancia correspondiente desde allí.
De esta forma, el operador "==" devuelve true para dos referencias de objetos que representan el mismo valor .
Esto es útil cuando los objetos similares se utilizan con mucha frecuencia y la creación de costos es costosa.
La documentación de la clase de cadena indica que la clase usa un grupo interno
La clase no está completa, surgen algunos problemas interesantes cuando tratamos de recorrer el contenido del objeto al implementar la interfaz CharSequence, pero este código es suficientemente bueno para mostrar cómo se podría aplicar ese elemento en el Libro.
Es importante tener en cuenta que al utilizar el objeto interno Pool, las referencias no se publican y, por lo tanto, no son de colección de basura, y eso puede convertirse en un problema si se crean muchos objetos.
Funciona para la clase String porque se usa intensivamente y la agrupación está constituida solo por objetos "internos".
Funciona bien para la clase Boolean también, porque solo hay dos valores posibles.
Y finalmente esa es también la razón por la cual valueOf(int) en la clase Entero está limitado a -128 a 127 valores int.
CaseInsensitiveString y String son objetos diferentes. No puedes hacer:
CaseInsensitiveString cis = "Polish";
porque "Polaco" es una Cadena, no una Cadena CaseInsensible. Si String extendiera Cadena CaseInsensitiveString, entonces estaría bien, pero obviamente no es así.
Y no te preocupes por la construcción aquí, no estarás fabricando objetos innecesarios. Si observa el código del constructor, todo lo que hace es almacenar una referencia a la cadena que pasó. No se está creando nada extra.
En el caso String s = new String ("foobar") está haciendo algo diferente. Primero está creando la cadena literal "foobar", y luego crea una copia creando una cadena nueva. No hay necesidad de crear esa copia.
Creo que el principal beneficio de usar la forma literal (es decir, "foo" en lugar de nueva cadena ("foo")) es que todos los literales de cadena son "internados" por la máquina virtual. En otras palabras, se agrega a un grupo de manera que cualquier otro código que crea la misma cadena usará el String mancomunado en lugar de crear una nueva instancia.
Para ilustrar, el siguiente código se imprimirá verdadero para la primera línea, pero falso para el segundo:
System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));
El hecho de que tenga la palabra String
en su clase, no significa que obtenga todas las características especiales de la clase de String
incorporada.
En Java, la sintaxis "texto" crea una instancia de la clase java.lang.String. La asignación:
String foo = "text";
es una tarea simple, sin necesidad de un constructor de copias.
MyString bar = "text";
Es ilegal hagas lo que hagas porque la clase MyString no es ni java.lang.String ni una superclase de java.lang.String.
En la mayoría de las versiones del JDK, las dos versiones serán las mismas:
String s = new String ("tonto");
String s = "Ya no es tonto";
Debido a que las cadenas son inmutables, el compilador mantiene una lista de constantes de cadenas y si intenta crear una nueva, primero verificará si la cadena ya está definida. Si es así, se devuelve una referencia a la cadena inmutable existente.
Para aclarar: cuando dices "String s =" estás definiendo una nueva variable que ocupa espacio en la pila, entonces si dices "Ya no es tonto" o una nueva Cadena ("tonto") sucede exactamente lo mismo: una nueva la cadena constante se compila en su aplicación y los puntos de referencia a eso.
No veo la distinción aquí. Sin embargo, para su propia clase, que no es inmutable, este comportamiento es irrelevante y debe llamar a su constructor.
ACTUALIZACIÓN: ¡Estaba equivocado! Basado en un voto negativo y un comentario adjunto, probé esto y me di cuenta de que mi entendimiento es incorrecto: una nueva Cadena ("Silly") crea una nueva cadena en lugar de reutilizar la existente. No estoy seguro de por qué sería esto (¿cuál es el beneficio?) ¡Pero el código habla más que las palabras!
En su primer ejemplo, está creando un String, "tonto" y luego lo pasa como un parámetro al otro constructor de copia de String, que crea un segundo String que es idéntico al primero. Debido a que Java Strings es inmutable (algo que frecuentemente molesta a las personas que están acostumbradas a las cadenas C), se trata de un desperdicio innecesario de recursos. En su lugar, debe usar el segundo ejemplo porque omite varios pasos innecesarios.
Sin embargo, el String literal no es un CaseInsensitiveString por lo que no puedes hacer lo que quieras en tu último ejemplo. Además, no hay forma de sobrecargar a un operador de casting como lo hace en C ++, por lo que literalmente no hay manera de hacer lo que quiera. En su lugar, debe pasarlo como un parámetro al constructor de su clase. Por supuesto, probablemente solo use String.toLowerCase () y terminé con esto.
Además, CaseInsensitiveString debería implementar la interfaz CharSequence, así como probablemente las interfaces Serializable y Comparable. Por supuesto, si implementa Comparable, también debe reemplazar equals () y hashCode ().
Es una ley básica que las cadenas en Java son inmutables y sensibles a mayúsculas y minúsculas.
Java crea un objeto String para cada literal de cadena que use en su código. Cada vez que se usa ""
, es lo mismo que llamar a una new String()
.
Las cadenas son datos complejos que simplemente "actúan" como datos primitivos. Los literales de cadena son en realidad objetos a pesar de que pretendemos que son literales primitivos, como 6, 6.0, ''c'',
etc. Por lo tanto, el "text"
literal de String devuelve un nuevo objeto String con el valor char[] value = {''t'',''e'',''x'',''t}
. Por lo tanto, llamando
new String("text");
en realidad es similar a llamar
new String(new String(new char[]{''t'',''e'',''x'',''t''}));
Con suerte desde aquí, puede ver por qué su libro de texto considera que esto es redundante.
Como referencia, aquí está la implementación de String: http://www.docjar.com/html/api/java/lang/String.java.html
Es una lectura divertida y podría inspirar algunas ideas. También es excelente para los principiantes leer y tratar de comprender, ya que el código demuestra un código muy profesional y compatible con las convenciones.
Otra buena referencia es el tutorial de Java en Strings: http://docs.oracle.com/javase/tutorial/java/data/strings.html
La mejor manera de responder a su pregunta sería familiarizarlo con el "conjunto constante de cadenas". En java, los objetos de cadena son inmutables (es decir, sus valores no se pueden cambiar una vez que se inicializan), por lo que al editar un objeto de cadena, se termina creando un nuevo objeto de cadena editado donde el objeto antiguo simplemente flota en una memoria especial llamada "cadena" grupo constante ". creando un nuevo objeto de cadena por
String s = "Hello";
solo creará un objeto de cadena en el grupo y las referencias se referirán a él, pero al usar
String s = new String("Hello");
crea dos objetos de cadena: uno en el grupo y el otro en el montón. la referencia se referirá al objeto en el montón.
Las cadenas de Java son interesantes. Parece que las respuestas han cubierto algunos de los puntos interesantes. Aquí están mis dos centavos.
las cadenas son inmutables (nunca puedes cambiarlas)
String x = "x";
x = "Y";
- La primera línea creará una variable x que contendrá el valor de cadena "x". La JVM buscará en su grupo de valores de cadena y verá si existe "x", si lo hace, apuntará la variable x hacia ella, si no existe, la creará y luego realizará la asignación.
- La segunda línea eliminará la referencia a "x" y verá si "Y" existe en el conjunto de valores de cadena. Si existe, lo asignará, si no lo hace, lo creará primero y luego la asignación. Como los valores de cadena se usan o no, se recuperará el espacio de memoria en el grupo de valores de cadena.
las comparaciones de cadenas dependen de lo que comparas
String a1 = new String("A");
String a2 = new String("A");
-
a1
no es igual aa2
-
a1
ya2
son referencias de objeto - Cuando la cadena se declara explícitamente, se crean nuevas instancias y sus referencias no serán las mismas.
Creo que estás en el camino equivocado al tratar de usar la clase caseinsensitive. Deja las cuerdas en paz. Lo que realmente te importa es cómo mostrar o comparar los valores. Use otra clase para formatear la cadena o para hacer comparaciones.
es decir
TextUtility.compare(string 1, string 2)
TextUtility.compareIgnoreCase(string 1, string 2)
TextUtility.camelHump(string 1)
Ya que está inventando la clase, puede hacer que las comparaciones hagan lo que quiera: compare los valores de texto.
Las cadenas se tratan especialmente en Java, son inmutables por lo que es seguro que se manejen por recuento de referencias.
Si tú escribes
String s = "Polish";
String t = "Polish";
entonces s y t en realidad se refieren al mismo objeto, y s == t devolverá verdadero, porque "==" para los objetos leídos "es el mismo objeto" (o puede, de todos modos, no estoy seguro de si esto es parte de la especificación del idioma real o simplemente un detalle de la implementación del compilador, por lo que tal vez no sea seguro confiar en esto).
Si tú escribes
String s = new String("Polish");
String t = new String("Polish");
entonces s! = t (porque ha creado explícitamente una nueva cadena) aunque s.equals (t) devolverá verdadero (porque la cadena agrega este comportamiento a iguales).
Lo que quieres escribir,
CaseInsensitiveString cis = "Polish";
no puede funcionar porque estás pensando que las citas son una especie de constructor de cortocircuito para tu objeto, cuando en realidad esto solo funciona para las antiguas java.lang.Strings.
No puedes. Las cosas entre comillas dobles en Java son especialmente reconocidas por el compilador como Strings, y desafortunadamente no se puede anular (o extender java.lang.String
- se declara final
).
Primero, no puede hacer una clase que se extienda desde String, porque String es una clase final. Y java administra cadenas de manera diferente a otras clases, por lo que solo con String puedes hacer
String s = "Polish";
Pero con tu clase debes invocar al constructor. Entonces, ese código está bien.
Si lo entendí correctamente, su pregunta significa por qué no podemos crear un objeto asignándole directamente un valor, no lo restrinjamos a una clase Wrapper of String en java.
Para responder que solo diría, los lenguajes de Programación Orientada a Objetos tienen algunos constructos y dice que todos los literales, cuando se escriben solos, se pueden transformar directamente en un objeto del tipo dado.
Eso significa precisamente que, si el intérprete ve 3, se convertirá en un objeto Integer porque integer es el tipo definido para dichos literales.
Si el intérprete ve algo en comillas simples como ''a'', creará directamente un objeto de tipo carácter, no necesita especificarlo ya que el lenguaje define el objeto predeterminado de tipo carácter para él.
De forma similar, si el intérprete ve algo en "" se considerará como un objeto de su tipo predeterminado, es decir, cadena. Este es un código nativo que funciona en segundo plano.
Gracias al curso de conferencia de video MIT 6.00 donde obtuve la pista para esta respuesta.
Solo agregaría que Java tiene constructores de Copias ...
Bueno, ese es un constructor ordinario con un objeto del mismo tipo que argumento.
String es una de las clases especiales en las que puedes crearlas sin la nueva parte de Sring
es lo mismo que
int x = y;
o
char c;
cuando dicen escribir
String s = "Silly";
en lugar de
String s = new String("Silly");
lo dicen al crear un objeto String porque las dos instrucciones anteriores crean un objeto String pero la nueva versión String () crea dos objetos String: uno en heap y el otro en el grupo de constante de cadena. De ahí que use más memoria.
Pero cuando escribes
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
no está creando una Cadena sino que está creando un objeto de la clase CaseInsensitiveString. Por lo tanto, necesita usar el nuevo operador.
CaseInsensitiveString
no es una String
aunque contiene una String
. Un literal de String
por ejemplo, "ejemplo", solo se puede asignar a una String
.
String
es una clase incorporada especial del lenguaje. Es solo para la clase String
en la que debes evitar decir
String s = new String("Polish");
Porque el literal "Polish"
ya es de tipo String
, y estás creando un objeto extra innecesario. Para cualquier otra clase, diciendo
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
es lo correcto (y solo, en este caso) que hacer.
String
son especiales en Java: son inmutables y las constantes de cadena se convierten automáticamente en objetos String
.
No hay forma de que su SomeStringClass cis = "value"
aplique a cualquier otra clase.
Tampoco se puede extender String
, ya que se declara como final
, lo que significa que no se permite subclasificación.
String str1 = "foo";
String str2 = "foo";
Tanto str1 como str2 pertenecen al mismo objeto String, "foo", b''coz Java maneja Strings en StringPool, por lo que si una nueva variable hace referencia a la misma cadena, no crea otra, sino que asigna el mismo alerady presente en StringPool .
String str1 = new String("foo");
String str2 = new String("foo");
Aquí str1 y str2 pertenecen a diferentes objetos, b''coz new String () crea un nuevo String Object a la fuerza.
String s1="foo";
literal irá en pool y s1 se referirá.
String s2="foo";
esta vez comprobará que el literal "foo" ya está disponible en StringPool o no como ahora existe, por lo que s2 hará referencia al mismo literal.
String s3=new String("foo");
El literal "foo" se creará en StringPool primero y luego a través de string arg constructor Se creará String Object, es decir, "foo" en el montón debido a la creación de objetos a través de un nuevo operador, luego s3 lo referirá.
String s4=new String("foo");
lo mismo que s3
tan System.out.println(s1==s2);// **true** due to literal comparison.
y System.out.println(s3==s4);// **false** due to object
comparación (s3 y s4 se crean en diferentes lugares en el montón)