Por que não está chamando um método estático por meio de uma instância um erro para o compilador Java?

StackOverflow https://stackoverflow.com/questions/610458

  •  03-07-2019
  •  | 
  •  

Pergunta

Tenho certeza que todos vocês sabem o comportamento que eu significo - código como:

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

provoca um aviso do compilador. Por que não é um erro?

EDIT:

Para ser claro: pergunta não tem nada a ver com Threads. Eu percebo exemplos de Tópicos muitas vezes são dadas quando se discute este por causa do potencial para realmente bagunçar as coisas com eles. Mas realmente o problema é que tal uso é sempre absurdo e você não pode (competência) escrever tal chamada e dizer isso. Qualquer exemplo deste tipo de chamada de método seria barmy. Aqui está outra:

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

O que faz com que pareça como se cada instância de String vem com um "String valueOf (int i)" método.

Foi útil?

Solução

Basicamente eu acredito que os designers de Java cometeu um erro quando projetaram a língua, e é tarde demais para corrigi-lo devido aos problemas de compatibilidade envolvidos. Sim, ele pode levar a muito enganosa código. Sim, você deve evitá-lo. Sim, você deve se certificar que seu IDE está configurado para tratá-la como um erro, IMO. Se você alguma vez projetar uma linguagem de si mesmo, ter isso em mente como um exemplo do tipo de coisa a evitar:)

Apenas para responder a ponto de DJClayworth, aqui está o que é permitido em 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 que eu acho que é enganosa? Porque se eu olhar para someVariable.SomeMethod() código que eu esperava que usar o valor de someVariable . Se SomeMethod() é um método estático, que a expectativa é inválido; o código está me enganando. Como isso pode eventualmente ser um boa coisa?

Curiosamente suficiente, Java não vai deixar você usar uma variável não inicializada potencialmente para chamar um método estático, apesar do fato de que a única informação que vai usar é o tipo declarado da variável. É uma bagunça inconsistente e inútil. Por que permitir que ele?

EDIT: Esta edição é uma resposta à resposta de Clayton, que reivindicações que permite herança para métodos estáticos. Isso não acontece. Os métodos estáticos simplesmente não são polimórficos. Aqui está uma pequena mas completa programa para demonstrar 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 você pode ver, o valor-tempo de execução de b é completamente ignorado.

Outras dicas

Por que deveria ser um erro? A instância tem acesso a todos os métodos estáticos. Os métodos estáticos não pode mudar o estado da instância (tentando é um erro de compilação).

O problema com o exemplo bem conhecido que você dá é muito específico para tópicos , e não chamadas de métodos estáticos. Parece que você está recebendo o activeCount() para o segmento a que se refere thread, mas você está realmente começando a contagem para o segmento chamado. Este é um erro lógico que você como um programador está fazendo. Emitir um aviso é a coisa apropriada para o compilador para fazer neste caso. É até você para prestar atenção à advertência e corrigir o seu código.

EDIT: eu percebo que a sintaxe da linguagem é o que é permitindo que você escreva enganosa código, mas lembre-se que o compilador e suas advertências são parte da linguagem também. A linguagem permite que você faça algo que o compilador considera duvidoso, mas dá-lhe o aviso para se certificar de que você está ciente de que poderia causar problemas.

Eles não podem torná-lo um erro mais, por causa de todo o código que já está lá fora.

Estou com você em que ele deve ser um erro. Talvez deve haver uma opção / profile para o compilador para atualizar alguns avisos para erros.

Update: Quando eles introduziram o assert palavra-chave no 1.4, que tem problemas de compatibilidade potenciais semelhantes com código antigo, eles fizeram isso disponível somente se você definir explicitamente o modo de fonte para '1.4' . Suponho que se poderia fazer um que um erro em um novo modo de fonte "java 7". Mas duvido que iria fazê-lo, considerando que todos os problemas que isso causaria. Como já foi salientado, não é estritamente necessário para impedi-lo de escrever código confuso. E as alterações de linguagem para Java deve ser limitado ao estritamente necessário neste momento.

A resposta mais curta - a linguagem permite que ele, por isso não é um erro

.

Provavelmente pela mesma lógica que faz com que este não é um erro:

public class X
{
    public static void foo()
    {
    }

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

A coisa realmente importante, do ponto de vista do compilador, é que ele seja capaz de resolver símbolos. No caso de um método estático, ele precisa saber que classe de olhar dentro para ele - uma vez que não está associado a qualquer objeto particular. os designers do Java decidiu, obviamente, que uma vez que poderiam determinar a classe de um objeto, eles também poderiam resolver a classe de qualquer método estático para esse objeto a partir de qualquer instância do objeto. Eles escolhem para permitir isso - balançou, talvez, por @ observação de TofuBeer - para dar o programador alguma conveniência. Outros designers de linguagem fizeram escolhas diferentes. Eu provavelmente teria caído no último campo, mas não é assim tão grande de um negócio para mim. Eu provavelmente iria permitir o uso que @TofuBeer menciona, mas ter permitido que a minha posição sobre não permitindo o acesso de uma variável de instância é menos sustentável.

Não é um erro, porque isso é parte da especificação, mas você está, obviamente, perguntando sobre a razão, que todos nós podemos adivinhar.

Meu palpite é que a fonte desta é realmente para permitir que um método em uma classe para invocar um método estático na mesma classe, sem o incômodo. Desde chamando x () é legal (mesmo sem o nome da classe self), chamando this.x () deve ser legal, bem como, e, portanto, chamando através de qualquer objeto foi feito legal também.

Isso também ajuda a incentivar os usuários a transformar funções privadas em estática se não alterar o estado.

Além disso, compiladores geralmente tentam evitar declarar erros quando não há nenhuma maneira que isso poderia levar a um erro direto. Desde um método estático não muda o estado ou cuidado sobre o objeto de chamada, ele não causa um erro real (apenas confusão) para permitir isso. Um aviso é suficiente.

O objetivo da referência de instância variável é apenas para fornecer o tipo que envolve o estático. Se você olhar o código byte invocando uma estática via instance.staticMethod ou EnclosingClass.staticMethod produz o mesmo método bytecode invocação estática. Nenhuma referência aos aparece instância.

A resposta, como também por isso que ele está lá, bem, apenas é. Contanto que você use a classe. e não através de um exemplo, você vai ajudar a confusão evitar no futuro.

Provavelmente você pode alterá-la em seu IDE (em Preferências do Eclipse -> Java -> Compiler -> Erros / avisos)

Não há opção para ele. Em java (como muitos outros lang.) Você pode ter acesso a todos os membros estáticos de uma classe através de seu nome de classe ou instância objeto dessa classe. Isso seria até você e sua solução caso e software que você deve usar que lhe dá mais capacidade de leitura.

Eu só considere o seguinte:

instanceVar.staticMethod();

para ser abreviada para isso:

instanceVar.getClass().staticMethod();

Se você sempre tinha que fazer isso:

SomeClass.staticMethod();

então você não seria capaz de herança alavanca para métodos estáticos.

Isto é, chamando o método estático através da instância você não precisa saber o que classe concreta a instância é em tempo de compilação, só que ele implementa staticMethod em algum lugar () ao longo da cadeia de herança.

EDIT: Esta resposta está errada. Veja os comentários para mais detalhes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top