2009-02-16 7 views
7

Tengo una clase de datos en mi aplicación. Mi aplicación nunca se usará como API pública y seré la única persona que desarrolle código dentro de mi proyecto.En Java, ¿es una mala idea hacer públicos los miembros de un objeto?

Estoy tratando de ahorrar cada onza de poder de procesador y memoria que pueda.

¿Es una mala idea hacer que mis miembros de datos en mi clase de datos tengan protección pública/protegida/predeterminada para que no tenga que usar un getter? Usar un getter requeriría un poco más de memoria y la creación de una pila y tal ... lo que creo que no es necesario. La única razón por la que puedo ver al usar un getter es por protección/privacidad, pero si soy el único programador y nadie más va a usar mi API, ¿es una mala idea no usar getters?

Háganme saber si esto es estúpido.

+1

Unos pocos ciclos de reloj serían todo lo que perdería. Las micro optimizaciones realmente no ayudan y terminan perjudicándote porque, como desarrollador, tienes que recordar más, e introduce más lugares para los errores y reduce la legibilidad. Te recomiendo que no lo hagas. – Malfist

+0

Ese es un buen punto. Supongo que tal vez debería medir el código w/getters y w/o, y ver si realmente termina siendo algo significativo. – jbu

+0

No será, no se moleste, –

Respuesta

3

Esto es un poco herético, pero estoy de acuerdo con usted en que si sabe que nadie más va a utilizar su clase, puede omitir esas cosas. No lo haría en un código que podría reutilizarse, incluso oculto detrás de una API, pero en su caso parece razonablemente seguro.

+0

Recitaré eso, me suena a sentido común –

+0

Um, todos los que usaban fechas de dos dígitos en la década de 1960 sabían que no podrían desarrollarse en un problema posterior ... –

+0

... y en una pequeña aplicación insertada en la memoria, una fecha de 2 dígitos es probablemente * aún * la elección correcta. –

2

Estoy bastante seguro de que la cantidad de memoria utilizada es insignificante. La JVM podría incluso optimizar las llamadas para que estén en línea dependiendo de la implementación en tiempo de ejecución si compila para producción. Si lo está desarrollando usted mismo, aún puede ser útil porque si tiene un error difícil de rastrear puede establecer un punto de interrupción en el captador/instalador y ver exactamente cuándo está cambiando los valores. Tampoco debería haber ningún código para escribir, porque la mayoría de los IDE modernos tienen funciones para generar el código automáticamente.

+0

Esa es otra cosa que detesto acerca de leer código Java ... los cientos y cientos de líneas de código CRAP inútiles escritas por IDEs. –

1

No es estúpido, pero creo que tampoco es una buena idea.

Entiendo la tentación ... si nadie más está usando el código, entonces no tiene que preocuparse por ello. Pero una y otra vez, resulta que esto no coincide con lo que realmente sucede ... descubres que lo usarás en más lugares de los que creías, o el proyecto se vuelve más grande de lo esperado, o alguien simplemente se apodera de él y piensa que es útil ... las cosas que nunca debieron ser permanentes o públicas tienen una forma de convertirse en eso.

¿Existe realmente ese límite apretado en la potencia y la memoria del procesador? No sé sobre su situación (¿aplicación integrada, quizás?), Pero como una regla (sobregeneralizada), es mejor que busque recursos en otra parte ... en sus estructuras de datos, algoritmos o arquitectura para ver mejores mejoras en memoria o CPU.

+0

Desearía que alguien escribiera un comentario aquí acerca de por qué esto fue desestimado ... parece relativamente inofensivo. – Beska

8

Es probable que los getters y setters triviales se incluyan de todos modos, pero en los campos públicos habrá perdido la distinción entre el contrato (API) y la implementación. Incluso si esto es solo una API que usará, es bueno mantener las cosas ligeramente acopladas a IMO.

4

La gente de Python no usa getters y no están ardiendo en el infierno.

Getter/setter es una forma de exponer parte de la clase a la simple introspección de Java. La especificación de Java Bean se basa en tener getters y setters públicos como una forma de determinar qué atributos son importantes.

Si bien es esencial para cosas que requieren/producen/usan granos, no es una característica esencial de la programación OO o la programación Java. Es solo parte de las especificaciones de Bean, y se requiere para cualquier clase que quiera participar en cosas parecidas a las judías.

Los atributos públicos están bien. Son simples, directos y obvios.

+0

Python tiene una convención donde los miembros "privados" tienen un prefijo común "_". La idea es que no los uses a menos que sepas lo que estás haciendo. –

+0

@Chase Seibert: Si bien es cierto que _ significa "privado", no desperdiciamos mucho tiempo en escribir getters y setters. –

+0

El único problema con los atributos públicos es que pueden ser una buena idea cuando los implemente, pero luego puede restringirlo en el camino cuando desea un mayor control sobre sus conjuntos/objetos. – cdmckay

0

Cualquier uso de la pila va a ser altamente transitorio y no es una certeza de todos modos. Puede encontrar que el compilador optimiza cualquier sobrecarga innecesaria de todos modos, por lo que puede descubrir que no gana nada en términos reales.

Acepto que no es necesariamente malo para una clase privada que no sea API utilizar miembros públicos, pero lo que obtienes es tan pequeño (si es que hay alguno) Simplemente no me molestaría.

1

Nunca se sabe, siempre se codifica como si las personas que leen tu código saben dónde vives y eres asesino en serie. Incluso si desarrolla código solo para usted, intente (imo) hacerlo como si estuviera desarrollando en un equipo. De esta manera te acostumbras a construir un código legible de mejores prácticas. En cuanto a la sobrecarga de rendimiento, tal vez es mejor hacerlo en algo así como C, si realmente realmente necesita cada bit de su memoria y cada ciclo de su CPU.

0

Desde la perspectiva de quién ha escrito el código y quién lo va a usar, no importa si es usted o alguien más, es posible que aún necesite getters y setters, si es que alguien lo usa más adelante. es una API pública de facto.

Sin embargo, si realmente solo se trata de datos y no necesita ningún comportamiento asociado con la clase, significa que los miembros deben ser públicos.

Para mí es si la clase tiene algún comportamiento o si desea cambiar los nombres o tipos de sus miembros de datos como detalles de implementación que realmente importan.

En cuanto a la potencia del procesador y la memoria, ¿ha medido?

24

Si está reemplazando getters/setters por optimización de rendimiento/memoria, entonces está tomando el enfoque equivocado. Es casi seguro que esta no será la razón por la cual su aplicación se ejecuta lentamente o usa demasiada memoria.

El pecado capital de la optimización es hacerlo antes de que sepa que lo necesita. Optimice solo cuando tenga información real que le muestre dónde se desperdicia la mayor cantidad de tiempo/memoria y luego dedique su tiempo a optimizarla. La idea detrás de esto es que ganarás más al reducir el 5% del tiempo en un código que ocupa el 80% del tiempo total de ejecución, en lugar de afeitar incluso el 20% en un código que solo contribuye con un 5%. el tiempo de ejecución total. (Lo mismo se aplica a la memoria).

Además, tendría cuidado al diseñar la aplicación como sugiere, ya que significa que algunas propiedades (p. Ej .: propiedades simples) serán directamente accesibles, mientras que otras (propiedades derivadas más complejas, o propiedades donde no querer exponer los tipos subyacentes) tendrá getters/setters. Por lo tanto, terminará con una combinación de estilos de acceso, que será menos sostenible.

4

Como con cualquier optimización, mida antes y después para ver si hay algún beneficio que justifique los inconvenientes.

Creo que encontrará que no hará ninguna diferencia notable en el rendimiento de su código (pero pruébelo usted mismo). La JVM alineará getters y setters usados ​​con frecuencia.

Utilice un generador de perfiles y encuentre los hotpsots reales en su aplicación. La optimización sin evidencia es solo conjeturas.

11

Es una mala idea para hacer miembros públicamente disponibles como una optimización. Como han dicho otros, prácticamente no tendrá impacto.Sin embargo, si el objeto es una estructura de datos simple con poco comportamiento, está bien escribirlo de esa manera. Siempre que lo haga por simplicidad y legibilidad, no por el rendimiento.

2

Considere que una vez que pone algo en una API pública que está escrito en piedra. No puede cambiar el nombre, no puede cambiar el tipo de letra, no puede cambiar cómo se almacena.

Ponerlo detrás de un método no da como resultado una penelidad de rendimiento en una máquina virtual moderna (casi nada en los últimos 10 años).

La flexibilidad que obtiene de tener métodos para obtener el valor es más importante en mi opinión ,.

Si decide hacerlas públicas, asegúrese de marcarlas como definitivas y de que son inmutables.

 
public class Point 
{ 
    public final int x; 
    public final int y; 

    public Point(final int xVal, final int yVal) 
    { 
     x = xVal; 
     y = yVal; 
    } 
} 

Editar:

Por API pública me refiero a cualquier variable que es público, no es que la propia clase sería parte de la API expuesta por otros desarrolladores. Al hacerlo público, puede causar problemas usted mismo más adelante (si fuera una API pública "real" a la que otros desarrolladores tuvieron acceso, está literalmente grabada en piedra a menos que desee romper el código de otras personas cuando lanza una actualización).

1

En mi humilde opinión, para las propiedades que por su propia naturaleza están destinadas a contener pasivamente los datos y no podrían hacer nada más complicado sin cambiar completamente su significado desde la perspectiva del usuario API, getters y setters son simplemente innecesarios. Si la propiedad es, y por su naturaleza claramente siempre lo será, solo un titular de datos, como una clase que se usa de manera similar a una estructura C, simplemente haga pública esa estupidez. Como una declaración más general, las mejores prácticas pueden convertirse fácilmente en una pérdida de tiempo o incluso en las peores prácticas cuando se aplican con exceso de celo sin pensar en por qué son las mejores prácticas. Diablos, incluso goto está justificadamente justificado de vez en cuando.

2

Todos los problemas de optimización prematura se han discutido en las respuestas anteriores.

Sólo pensé que vale la pena mencionar que en Java se puede imitar estructuras de C mediante la definición de una clase con sólo los miembros públicos de este modo:

public class DataClass { 
    public int a; 
    public String b; 
    public char c; 
} 

y que se accederá (Obtención y establecimiento) solamente, haciendo referencia a esos miembros públicos.

Esta expresión idiomática es totalmente aceptable en algunos escenarios específicos.

+0

Prefiero usar un puntero opaco a eso: http://en.wikipedia.org/wiki/Opaque_pointer – TofuBeer

+0

Puntero opaco (o punteros en absoluto) no existe en Java ... –

2

Getters y setters no son solo para protección/privacidad. El uso principal es cambiar la forma en que expone los datos subyacentes.

Por ejemplo, en asp.net C# la propiedad visible de un control puede tener algo como:

private bool visible = true; 

public bool Visible 
{ 
    get 
    { 
     return visible && Parent.Visible; 
    } 
    set 
    { 
     visible = value; 
    } 
} 

La propiedad externa (de acceso/mutador) tiene un significado diferente a la variable subyacente. Además, si no tiene la funcionalidad anterior cuando comienza, cuando tiene conjuntos/conjuntos simples, se convierte en algo que puede agregar en una fecha posterior, fácilmente.

En cuanto al punto de rendimiento y ahorrar cada onza de procesador y memoria que pueda. Si esto va a tener un impacto notable, probablemente sea mejor que busque otro idioma.

1

inconvenientes potenciales para el uso de

public finaltipovar;

en lugar de

private finaltipovar;

publictipoget var var () {return;}

(lo que he experimentado personalmente) incluyen:

  • La perspectiva - sin embargo poco probable que parece ahora - que la representación será n para cambiar, en la clase base o en alguna subclase futura.

  • La posible incomodidad de mezclar campos expuestos de forma inmutable y mutable.

  • la molestia de recordar qué clases utilizan public final y que utilizan get var.

  • La molestia de explicar esta incoherencia a otra persona que más adelante vea el código fuente.

Nunca he sido capaz de convencerme de que valga la pena, aunque lo haya intentado.

0

Si la velocidad es tan crítica, podría valer la pena escribirla en C o C++.

+0

¿O ensamblado? ;-) – OscarRyz

+0

Nah, Java hoy en día es bastante rápido, dentro de épsilon de C/C++. Donde Java es realmente ineficiente es en el uso de la memoria. – dsimcha

+0

Desktop Java Java sacrifica memoria por velocidad. Las JVM pequeñas como jamvm o squawk usan mucha menos memoria pero no pueden correr tan rápido. –

2

Nunca he deseado tener un campo público en lugar de una propiedad, pero no puedo contar la cantidad de veces que he querido una propiedad y tenía un campo público. Eventualmente terminas queriendo lógica dentro de él.

+0

Exactamente ... e incluso si no cree que lo hará, ¿por qué no mantener la opción abierta? – cdmckay

+0

No debe tener lógica dentro de un descriptor de acceso. Puedo contar varias veces cuando he querido un campo y en su lugar una 'propiedad' (un accesorio que realmente hace otras cosas también) ha sido expuesto. –

1

He creado dos clases pequeñas, y las pruebo.

  • Primero he creado un solo objeto como prototipo.

  • Luego he creado una matriz de 2,000,000 para almacenarlos todos.

  • Luego, he ejecutado un ciclo, creo una nueva instancia allí y tomo los valores del prototipo.

Los resultados promedio en segundos que comparan cada uno es:

WithGS Without 
1.1323 1.1116 

Diff = 0.0207 secs. 

Por lo tanto, para este caso creo que sería mucho mejor tener una solución no optimizado primera, y una vez sin se necesitan más requisitos, proceda con el perfil.

Aquí está el código:

PersonGetSet.java 


public class PersonGetSet { 
    private String name; 
    private boolean deceased; 

    public void setName(String name) { 
     this.name = name; 
    } 
    public String getName() { 
     return name; 
    } 

    public void setDeceased(boolean deceased) { 
     this.deceased = deceased; 
    } 
    public boolean isDeceased() { 
     return this.deceased; 
    } 

    public static void main(String [] args) { 
     PersonGetSet pb = new PersonGetSet(); 
     pb.setName("name"); 
     pb.setDeceased(true) ; 

     long start = System.currentTimeMillis(); 
     PersonGetSet [] array = new PersonGetSet[2000000]; 
     for(int i = 0 ; i < array.length; i++) { 
      PersonGetSet personGs = new PersonGetSet(); 
      personGs.setName(pb.getName()); 
      personGs.setDeceased(pb.isDeceased()); 
      array[i] = personGs; 
     } 
     System.out.println("PersonGetSet took " + (System.currentTimeMillis() - start) + " ms. "); 
    } 
} 


Person.java 


public class Person { 
    String name; 
    boolean deceased; 
    public static void main(String [] args) { 
     Person pb = new Person(); 
     pb.name= "name" ; 
     pb.deceased = true; 

     long start = System.currentTimeMillis(); 
     Person [] array = new Person[2000000]; 
     for(int i = 0 ; i < array.length; i++) { 
      Person simplePerson = new Person(); 
      simplePerson.name= pb.name; 
      simplePerson.deceased = pb.deceased; 
      array[i] = simplePerson; 
     } 
     System.out.println("Person took " + (System.currentTimeMillis() - start) + " ms. "); 
    } 
} 
+0

Haría el paquete de clase local, haría los campos definitivos y los establecería con un constructor. De lo contrario, solo trata tu clase como una estructura de datos. –

+0

no, esta es una prueba mejor de lo que propones Peter. +1 –

+0

¿Por qué está almacenando sus objetos en una matriz de 2M cada vez? ¿Estás probando el GC? – eljenso

2

Creo que la inversa de esta pregunta es uno mejor que preguntar:

¿Puede ser una buena idea para hacer una Objetos miembros a disposición del público?

Con el desarrollo, generalmente es una buena idea abordar las cosas desde el principio de utilizar el menor nivel de accesibilidad requerido; en otras palabras, solo exponga tantos datos como necesite. Si aplica este principio en general, entonces se vuelve una práctica más común compartir solo todo lo que se requiere.

Así que con eso dicho, ¿por qué hacer esto?

0

Diseñar funcionalmente que nunca va a necesitar (getters/setters) es tan malo como la optimización prematura. Si esto es realmente solo para su uso, no lo haga público y luego estructure lo que crea que es lo más simple.

La optimización y/o getters solo deberían agregarse si realmente los necesita.

0

¿Necesita el captador en total? Es decir, ¿debería su objeto estar trabajando para usted, en lugar de que su cliente obtenga valores de datos y realice el trabajo por sí mismo?

Un aspecto clave de OOP es decirle a un objeto que haga algo, en lugar de extraer los bits y hacerlo usted mismo. por ejemplo

double ret = myObj.calculateReturn() 

vs

int v = myObj.getValue(); 
int ov = myObj.getOldValue(); 
double ret = (v-ov)/ov * 100; // do I work about dividing by zero etc.? 

cual veo mucho. A menudo necesitas getters (y setters, quizás), pero cuando escribo un getter siempre me pregunto si esos datos deberían estar expuestos, o si el objeto debería ocultarlo por completo para mí.

0

Es siempre una mala idea para hacer públicos los campos no finales.

¿Qué sucede si posteriormente desea agregar una notificación de evento?

¿Qué sucede si luego desea crear una subclase y cambiar el comportamiento?

¿Qué pasa si hay algunas restricciones de campo cruzado que desea aplicar?

TofuBeer muestra una clase Point con campos finales, está bien. Sin embargo, la clase Point en AWT no usa finales, y me causó mucha pena desde el principio en Java.

Estaba escribiendo un código 3D y quería subclase un punto tal que siempre que x & cambiara, podría ajustar automáticamente z según sea necesario. Debido a que los campos de Point eran públicos, ¡no había manera de saber cuándo cambiaron x o y!

1

Si su prioridad es el rendimiento, debe buscar en su elección de Java Virtual Machine y cómo se ejecutan los programas. El Desktop Java de Sun gasta MUCHO tiempo en la creación de perfiles y compila el código de bytes de Java en el código de máquina, lo que da como resultado programas que pueden ejecutarse muy rápido pero que usan mucha memoria.

Si encuentra que desea utilizar una JVM basada en HotSpot, debe buscar todos los trucos para ayudarla. Los getters y setters generalmente están en línea (es decir, se reemplazan directamente en el código de máquina, en lugar de llamar a una subrutina) y las constantes se pliegan. Las sentencias de conmutación para rangos pequeños generalmente se convierten en una tabla de salto.

Normalmente encuentro que el método "cabeza bajo el brazo" funciona bien para escribir la mayor parte del código, y luego se perfila el código de ejecución y se encuentran los cuellos de botella. Encontré por ejemplo que los StringBuffers son rápidos para muchas cosas, pero deleteCharAt (0) no es uno de ellos. Reescribir para usar una iteración simple sobre la cadena en lugar de eliminar en el buffer de cadena, hizo maravillas. También es probable que usted encuentre que los mayores beneficios están en los algoritmos, no en los accesos directos pequeños.

En el mundo C, el humano ya no puede ser más astuto que el compilador. En el mundo de Java, el ser humano puede ayudar a HotSpot escribiendo directamente en Java.

0

En nuestro equipo usamos la siguiente regla: si el estado representado por un campo de clase es mutable, siempre hazlo privado y proporcione mutadores; sin embargo, si es inmutable (es decir, no se reasignaría después de la creación de instancias de clase), se puede declarar como public final [type] [field-name], seguro para acceder.

Por favor tenga en cuenta que aquí "estado inmutable" significa específicamente que el campo está declarado como final. No se debe confundir con public [immutable-type] [field-name] donde uno podría realizar la reasignación aunque la instancia de tipo inmutable sea inmutable.

Pls también tenga en cuenta que hay muchas buenas razones para tener acceso, incluso para un campo inmutable. Por ejemplo, en los casos en que se requiere realizar alguna acción (por ejemplo, comprobación de seguridad) en el momento en que se lee el campo.

0

El argumento de que este código solo va a ser para su propio uso es una trampa fácil de encontrar: este es el caso de la mayoría de los códigos, los bits expuestos públicamente suelen ser muy pequeños. Asumiendo que la mayoría de los códigos son para uso privado, ¿por qué molestarse en usar preguntas privadas, protegidas, finales, const (C/C++), que conozco, pero espero que el punto esté claro?

La otra cosa que se echa de menos aquí es el bloqueo. Si accede directamente al miembro, solo podrá bloquear este código en el objeto completo o en el nivel de miembro. Y ese bloqueo estará en el control del código de uso, no del Objeto mismo. Quizás OK, quizás no, como en todas las cosas son caballos para los cursos.

0

Si el rendimiento es crítico, sugiero que los campos sean privados si solo se accede a ellos en la misma clase o el paquete local si se accede a ellos en otra clase. Si le da a una clase interna/anidada campos privados, el compilador agregará/usará métodos de acceso (ya que la VM no permite que las clases accedan a campos en otra clase aunque Java lo haga)

Tener campos mutables públicos sugiere un problema de diseño a mi. Tener un código de rendimiento crítico dividido entre los paquetes no sugiere el tipo de codificación estricta que necesita para el código de rendimiento crítico.

Si tiene campos inmutables, no tengo problemas para hacer público el campo, siempre que espere un mayor costo de desarrollo si los campos cambian el comportamiento. De hecho, sugiero utilizar campos públicos inmutables, si cree que esto hace que el código sea más simple/más fácil de entender.

Sin embargo, la primera prioridad debe ser la legibilidad del código. El código más simple a menudo rinde mejor también.

0

En general: si desea optimizar algo manualmente, debe considerar mejoras arquitectónicas en lugar de tales microoptimizaciones. Las microoptimizaciones pueden, en muchos casos, hacerse automáticamente con una herramienta.

Para Java: Hay una herramienta ProGuard, que puede hacer muchas optimizaciones. Sin embargo, si usa una JVM moderna (digamos HotSpot o OpenJDK), la JVM puede hacer estas optimizaciones Just-In-Time. Si tiene una aplicación de larga ejecución, ProGuard probablemente tendrá un efecto menor en el rendimiento.

Cuestiones relacionadas