Estoy seguro que todos ustedes saben el comportamiento que quiero decir – código, tales como:

Thread thread = new Thread();
int activeCount = thread.activeCount();

provoca una advertencia del compilador. ¿Por qué no es un error?

EDICIÓN:

Para ser claros: la pregunta no tiene nada que ver con los Hilos. Me doy cuenta de Hilo de ejemplos se dan a menudo cuando se habla de esto, ya que realmente el potencial de complicar las cosas con ellos. Pero realmente el problema es que su uso está siempre tonterías y no se puede (competente) escribir una llamada y en serio. Algún ejemplo de este tipo de llamada al método sería loco. Aquí es otra:

String hello = "hello";
String number123AsString = hello.valueOf(123);

Que hace que se vea como si cada instancia de String viene con un «String valueOf(int i)» método.

  • Extender en su punto, el redundantes instancia, incluso puede ser null: String hello = null; hello.valueOf(123); funciona!
InformationsquelleAutor tmtest | 2009-03-04

11 Comentarios

  1. 78

    Básicamente creo que el Java diseñadores cometió un error cuando se diseñó el lenguaje, y es demasiado tarde para arreglarlo, debido a los problemas de compatibilidad de los involucrados. Sí, puede conducir a muy engañosa código. Sí, usted debe evitar. Sí, usted debe asegurarse de que la IDE está configurado para tratarlo como un error, de la OMI. Si alguna vez te diseñar un lenguaje en sí mismo, tenerlo en cuenta como un ejemplo del tipo de cosas a evitar 🙂

    Sólo para responder a DJClayworth punto, aquí es lo que está permitido en C#:

    public class Foo
    {
        public static void Bar()
        {
        }
    }
    
    public class Abc
    {
        public void Test()
        {
            //Static methods in the same class and base classes
            //(and outer classes) are available, with no
            //qualification
            Def();
    
            //Static methods in other classes are available via
            //the class name
            Foo.Bar();
    
            Abc abc = new Abc();
    
            //This would *not* be legal. It being legal has no benefit,
            //and just allows misleading code
            //abc.Def();
        }
    
        public static void Def()
        {
        }
    }

    ¿Por qué creo que es engañosa? Porque si miro el código someVariable.SomeMethod() espero que utilizar el valor de someVariable. Si SomeMethod() es un método estático, esa expectativa no es válido; el código es engañar a mí. ¿Cómo puede posiblemente ser un buena cosa?

    Extrañamente suficiente, Java no permite el uso potencialmente a una variable no inicializada para llamar a un método estático, a pesar del hecho de que la única información que se va a utilizar es el tipo declarado de la variable. Es un incoherente e ineficiente lío. ¿Por qué lo permite?

    EDIT: Esta edición es una respuesta a Clayton respuesta, que afirma que permite la herencia de métodos estáticos. No. Los métodos estáticos no sólo son polimórficos. He aquí un breve pero completo programa para demostrar que:

    class Base
    {
        static void foo()
        {
            System.out.println("Base.foo()");
        }
    }
    
    class Derived extends Base
    {
        static void foo()
        {
            System.out.println("Derived.foo()");
        }
    }
    
    public class Test
    {
        public static void main(String[] args)
        {
            Base b = new Derived();
            b.foo(); //Prints "Base.foo()"
            b = null;
            b.foo(); //Still prints "Base.foo()"
        }
    }

    Como se puede ver, la ejecución de valor de tiempo de b es completamente ignorado.

    • Creo que usted puede ser que falte algo. Ver mi post.
    • Nope. Eso es permitido en C#, pero someInstanceOfMyClass.doComplexCalculation() no lo sería.
    • Corrí una prueba similar y confirmó sus conclusiones. Basado en eso estoy de acuerdo que es malo para Java para permitir que los métodos estáticos para ser llamado desde una instancia var. No es la capacidad adquirida (como yo pensaba originalmente), pero el potencial para la confusión o el error es mayor.
    • El tiempo de ejecución valor de b es completamente ignorado porque se llama a un método estático, que sólo depende de la clase de b no su valor. Todos los valores de tipo de Base tienen el mismo método. Declarado de la Base b, entonces b es una Base , no es un Derivado . Si usted ha declarado Derivados de b habría impreso «de la que Deriva.foo()» .
    • Sí, lo sé… no estoy seguro de en qué punto estás tratando de hacer. (Yo personalmente no decir que «todos los valores de tipo de Base tienen el mismo método» – una instancia no «tiene» un método del todo… pero creo que sé lo que quieres decir.)
    • El punto es que una instancia (como en la programación orientada a objetos «es un / tiene una» relaciones de todos sus miembros de la clase. Sólo el inverso no es cierto: una clase tiene sólo sus miembros de la clase, es decir,. los miembros estáticos, no los miembros de instancia. Esta sintaxis no es muy diferente de una instancia (o una clase) que los miembros a través de la herencia. Como mencioné en un comentario a otra respuesta a esta pregunta, la sintaxis de la ambigüedad no es muy diferente de un método de instancia tener en su ámbito de aplicación a un miembro de instancia global de toda la instancia.
    • Yo personalmente no creo que tiene sentido pensar en métodos estáticos de esa manera – y claramente el C# diseñadores no sea evitar inútiles errores.
    • Skeet : Bueno, el C++ diseñadores parecía pensar esta sintaxis es ACEPTAR. También permite el uso práctico que he mencionado en mi comentario en la otra respuesta a esta pregunta stackoverflow.com/questions/610458/… .
    • Que el «uso práctico» no sería aplicable, ya sea en Java o C#, por lo que tiene más sentido que la prohibición. C++ es un lenguaje diferente en muchas, muchas maneras.
    • C# es también un idioma diferente. ¿Por qué no mi ejemplo práctico ser «aplicable» en Java? Si usted quiere un único método para aceptar una instancia que podría ser el tipo de Base o tipo de Derivados, y llamar al método estático apropiado bien, ¿por qué no utilizar el sencillo, claro patrón de herencia he aplicado? De lo contrario, usted tiene que utilizar condicionales o algo más frágil/verbose.
    • Porque sería una violación de lo que static significa en todas partes los demás en el lenguaje. Un método estático no está asociado con una instancia de este tipo; se asocia con el tipo en sí. Asimismo métodos estáticos sólo no anular el uno al otro. Si usted está diciendo: «El lenguaje debe haber sido diseñado de forma completamente diferente», entonces eso es una cosa, pero es que no una excusa para la forma en que Java funciona en realidad en el momento (en términos de permitir este acceso) – y el «beneficio» que estás abrazando ni siquiera funciona en Java de todos modos.
    • Permítanos continuar esta discusión en el chat.
    • Estoy usando IntelliJ de 2017 y el comportamiento predeterminado es NO auto completar métodos estáticos cuando se utiliza instancia. Si lo haces de todos modos, se establece una advertencia (pero esta acción es realizada por el IDE, no el compilador).

  2. 13

    ¿Por qué debería ser un error? La instancia tiene acceso a todos los métodos estáticos. Los métodos estáticos no pueden cambiar el estado de la instancia (tratando de es un error de compilación).

    El problema con el conocido ejemplo que dan es muy específico hilos, no llamadas a métodos estáticos. Parece como si usted está recibiendo el activeCount() para el hilo mencionado por thread, pero usted está consiguiendo realmente el recuento para el subproceso de llamada. Esto es un error lógico que el programador está haciendo. La emisión de una advertencia es el apropiado para el compilador de hacerlo en este caso. Es hasta usted para prestar atención a la advertencia y corregir el código.

    EDIT: me doy cuenta de que la sintaxis del lenguaje es lo que permitiendo a escribir engañosa código, pero recuerde que el compilador y sus advertencias son parte de la lengua también. El lenguaje le permite hacer algo que el compilador considera dudosa, pero da la advertencia para asegurarse de que eres consciente de que podría causar problemas.

    • Es irrelevante para el ejemplo. La única cosa es la tipo declarado de la variable. Es una horrible, horrible misfeature y un error en la parte de la lengua de los diseñadores, de la OMI.
    • Sí, es irrelevante a la instancia, pero no creo que llamar a un método estático de una instancia debería ser un completo error. Es realmente de mal estilo. En mi humilde opinión, de una clase deben ser todos los métodos estáticos, o los métodos estáticos deben ser privadas, pero yo no quiero que el compilador para reforzar eso.
    • No creo que incluso dio una advertencia en los primeros días. La advertencia fue añadida a causa de que estaba engañando a las personas. ¿Cuál es la beneficios en permitirle?
    • Pongámoslo de esta manera – si Java no permite y alguien sugirió que debe lo permiten, ¿cuál sería tu reacción? ¿Realmente argumentar a favor de ella? O tendría que argumentar (como yo) que es un inútil característica que innecesariamente permite engañosa código?
    • La ventaja de permitir que se podría probablemente sólo se expresa en tiempo de compilación. No hay ninguna razón desde nuestro punto de vista a tener que llamar a un método estático de una instancia. Ya que ninguna otra característica del lenguaje sería no permitir que, los primeros ejecutores probablemente lo dejaron como aparentemente innecesario de verificación.
    • Estoy de acuerdo, sin embargo, que si se tratara de un error desde el principio, yo no diría en favor de permitir que él. Ya puedes llamar <Clase>.staticMethod(), así que no hay realmente ninguna necesidad de <ejemplo>.staticMethod().
    • No me compre el «tiempo de compilación» razón – es obvio que usted está buscando el método a través de una referencia; ¿cuánto tiempo después de tomar para comprobar si es o no es estática? Creo que es más fácil simplemente consideramos que es un lenguaje de diseño de error.
    • Pero no tiene la retrospectiva de ver todo el código de malo nos iba a escribir sin una advertencia para que, ¿por qué poner una comprobación adicional cuando usted está escribiendo el compilador? La referencia tiene acceso a los métodos estáticos, por lo que la advertencia se requiere código adicional para comprobarlo.
    • Cuando estés escribiendo el compilador, por lo que está obligado por el lenguaje. Sin embargo, yo diría que a la hora de diseñar el idioma que usted debe reconocer que es un error lo permiten. Nada llega a través de una expresión debería depender el valor de la expresión de alguna manera.
    • No sé lo obvio que es, sin el beneficio de la retrospectiva. Hay una buena razón para permitir el acceso a la electricidad estática de las variables miembro y los métodos de una instancia de una clase. Parece que no mucho de un tramo a permitir que a partir de las referencias así. La mayoría de las veces es inofensivo para las razones <continuó>
    • …Ya he explicado. No es hasta que está demostrado que los malos ejemplos de código que da lugar a que obviamente no es una buena cosa.
    • Es por eso que la mayoría de nosotros no debería ser el idioma de los diseñadores 🙂
    • No, que yo sepa a nadie, ni siquiera McCarthy, lo hace bien la primera vez. Además, estoy mucho más hábil en quejarse de idiomas existentes. 🙂

  3. 9

    Que no se puede hacer un error más, porque de todo el código que ya está ahí.

    Estoy con usted en que debe ser un error.
    Tal vez no debería ser una opción/profile para que el compilador para actualizar algunas advertencias a los errores.

    Actualización: Cuando se introdujo la afirmar palabra clave en la 1.4, que tiene un potencial similar de los problemas de compatibilidad con el viejo código, se hizo disponible sólo si se establece explícitamente el modo de fuente a «1.4». Supongo que uno podría hacer es un error en un nuevo modo de fuente de «java 7». Pero dudo que lo haría, teniendo en cuenta que todas las molestias que pueda causar. Como otros han señalado, no es estrictamente necesario para evitar que la escritura confusa código. Y los cambios de idioma de Java debe limitarse a lo estrictamente necesario en este punto.

    • No hay tal opción en Eclipse compilador (indirectStatic, help.eclipse.org/help33/index.jsp?topic=/…)
    • Pero lo hicieron cuando se presentó la aserción de palabras clave en Java 1.4. ¿Por qué no pueden volver a hacerlo en la misma forma?
    • Estás en lo correcto. Para hacer Valer, usted tiene que específicamente establece el compilador nivel a 1.4, de lo contrario, todavía se compila sin afirmar. Supongo 1.5 anotaciones y los medicamentos genéricos funcionan de la misma. Así que uno podría tener Java 7 compilar nivel, que sería un error.
  4. 2

    Probablemente por la misma lógica que hace que esto no es un error:

    public class X
    {
        public static void foo()
        {
        }
    
        public void bar()
        {
            foo(); //no need to do X.foo();
        }
    }
  5. 2

    Lo realmente importante, desde el compilador de la perspectiva, es que sea capaz de resolver los símbolos. En el caso de un método estático, se necesita saber qué clase de mirar por ella, ya que no está asociada con ningún objeto en particular. Java diseñadores, obviamente, decidió que, puesto que podría determinar la clase de un objeto, también podrían resolver la clase de cualquier método estático para que el objeto de cualquier instancia del objeto. Eligen a permitir esto-se tambaleó, tal vez, por @TofuBeer de observación — para dar el programador cierta comodidad. Otro idioma diseñadores han tomado decisiones diferentes. Probablemente me habría caído en el último campamento, pero no es un gran problema para mí. Probablemente tendría que permitir el uso que @TofuBeer menciona, pero después de haber permitido que mi posición de no permitir el acceso de una variable de instancia es menos sostenible.

  6. 2

    No es un error, porque es parte de la especificación, pero es obvio que está preguntando acerca de la justificación, de la que todos podemos imaginar.

    Mi conjetura es que el origen de esto es permitir que un método en una clase de invocar a un método estático en la misma clase, sin la molestia. Desde llamando x() es legal (incluso sin el auto nombre de la clase), llamando a esto.x() debería ser legal, y por lo tanto de llamadas a través de cualquier objeto fue hecho jurídico así.

    Esto también ayuda a motivar a los usuarios a su vez funciones privadas en estático si no cambia el estado.

    Además, los compiladores suelen intentar evitar declarar errores cuando no hay manera de que esto podría llevar a un error. Desde un método estático que no cambia el estado o la atención sobre el objeto invocante, que no causa un error real (sólo confusión) para permitir esto. Una advertencia suficiente.

    • Es bastante fácil de hacer que esté disponible dentro de la clase actual, sin especificar el nombre de la clase. C# conseguido, y los compiladores de Java administrar a notar la diferencia (ya que no obtendrá una advertencia en ese caso) así que ¿por qué debería ser especificado de esta manera?
  7. 2

    El propósito de la instancia de la variable de referencia es sólo para proporcionar el tipo que encierra la estática. Si miramos el código de bytes de la invocación de un estático a través de la instancia.staticMethod o EnclosingClass.staticMethod produce el mismo invocar el método estático de código de bytes. Ninguna referencia a la instancia aparece.

    La respuesta como también por qué está allí, así que simplemente es. Siempre que utilice la clase. y no a través de un ejemplo que ayudará a evitar confusiones en el futuro.

  8. 1

    Probablemente usted puede cambiar en su IDE (Eclipse Preferencias -> Java -> Compilador -> Errores/Advertencias)

  9. 0

    No hay opción para ello. En java (como muchos otros lang.) usted puede tener acceso a todos los miembros estáticos de una clase a través de su nombre de la clase o de la instancia de objeto de esa clase. Que sería de usted y de su caso y la solución de software que puedes usar que le da más legibilidad.

  10. -9

    Me consideren esto:

    instanceVar.staticMethod();

    a ser la abreviatura de esta:

    instanceVar.getClass().staticMethod();

    Si usted siempre ha tenido que hacer esto:

    SomeClass.staticMethod();

    entonces no vas a ser capaz de sacar provecho de la herencia de métodos estáticos.

    Que es, llamando al método estático a través de la instancia que usted no necesita saber lo concreto de la clase de la instancia en tiempo de compilación, sólo que implementa staticMethod() en algún lugar a lo largo de la cadena de herencia.

    EDIT: Esta respuesta es errónea. Ver los comentarios para más detalles.

    • Bueno, esa es otra razón por la que no debería ser permitido -, porque estás siendo engañado también. No actúan como usted desea. Será solo el uso de la declarado tipo de «instanceVar» en su ejemplo. Diablos, el valor de instanceVar incluso puede ser null.
    • Yo estaba bajo la impresión de que getClass() le daría la clase real del objeto, no el tipo declarado de la variable. Javadoc es claro en este tema, así que voy a probarlo.
    • Sí, pero no de la llamada getClass(). Voy a editar mi respuesta con un ejemplo.
    • (Y si ¿ llamada getClass(), que no podía, a continuación, llamar a staticMethod(), debido a que no es un método en la Clase<T>.)
    • Acepto la corrección. ejemplo.getClass().staticMethod() no compila. ejemplo.staticMethod() fui a la declarada clase, no de la clase. Parece que no hay forma de llamar a un método estático de una instancia de var superclase de la instancia, al menos no sin tener que recurrir a la Reflexión.
    • ¿Esto significa que tengo que downvote mi propio post?
    • Usted podría eliminarlo, y puedo editar mi post para que no se refieren a ella.
    • Voy a dejar aquí. Yo aprender tanto de los errores como cualquier otra cosa, por lo que podría ayudar a alguien a ver esto. Gracias por tu ayuda.
    • Usted puede querer hacer este wiki de la comunidad para que podamos downvote sin penalizarlo.
    • y penalizar a nosotros 🙂

Dejar respuesta

Please enter your comment!
Please enter your name here