Вопрос по static, java, coding-style, optimization – Какова выгода от объявления метода как статического

93

Недавно я просматривал свои предупреждения в Eclipse и наткнулся на это:

static warning

Он выдаст предупреждение компилятору, если метод может быть объявлен как статический.

[edit] Точная цитата в справке по Eclipse, с акцентом на приват и финал:

When enabled, the compiler will issue an error or a warning for methods which are private or final and which refer only to static members.

Да, я знаю, что могу выключить, но я хочуknow the reason for turning it on?

Why would it be a good thing to declare every method possible as static?

Даст ли это какой-либо выигрыш в производительности? (в мобильном домене)

Указывая на метод как статический, я полагаю, он показывает, что вы не используете какие-либо переменные экземпляра, поэтому могли бы быть перемещены в класс стиля utils?

В конце дня я должен просто отключить это "игнорировать" или я должен исправить 100+ предупреждений, которые он мне дал?

Как вы думаете, это просто дополнительные ключевые слова, которыеdirty код, так как компилятор просто вставит эти методы в любом случае? (вроде как вы не объявляете каждую переменную, которую можете завершитьbut you could).

Связанные с:stackoverflow.com/q/790281 Brian Rasmussen
Не уверен, но это может просто рассматриваться как помощь в программировании. Предупреждения - это просто указание на что посмотреть. James P.
Мне любопытно, какой вид функциональности выполняют эти методы. Возможно, что-то было сделано неправильно, если их так много. ArjunShankar

Ваш Ответ

9   ответов
3

1. Метод объявленияstatic дает небольшой выигрыш в производительности, но, что более полезно, он позволяет использовать его, не имея под рукой экземпляра объекта (например, о заводском методе или получении синглтона). Он также служит для документирования и описания характера метода. Эту документальную цель не следует игнорировать, так как она дает немедленную подсказку о природе метода читателям кода и пользователям API, а также служит инструментом мышления для первоначального программиста - четкое понимание предполагаемого значения помогает Вы также мыслите прямо и создаете более качественный код (я думаю, основываясь на моем личном опыте, но люди разные). Например, логично и, следовательно, желательно различать методы, работающие с типом, и методы, действующие с экземпляром типа (как указано вДжон Скит в своем комментарии к вопросу C #).

Еще один вариант использования дляstatic методы для имитации интерфейса процедурного программирования. Думать оjava.lang.System.println() класс и методы и атрибуты в нем. Классjava.lang.System используется как пространство имен группировки, а не как экземпляр объекта.

2. Как Eclipse (или любой другой запрограммированный или другой вид - биоразлагаемый или небиокомпозиционный - объект) может точно знать, какой метод может быть объявлен как статический? Даже если базовый класс не обращается к переменным экземпляра или не вызывает нестатические методы, механизм наследования может измениться. Только если метод не может быть переопределен путем наследования подкласса, мы можем со 100% уверенностью утверждать, что метод действительно может быть объявленstatic, Переопределение метода невозможно точно в двух случаях

private (no subclass can use it directly and does not even in principle know about it), or final (even if accessible by the subclass, there is no way to change the method to refer to instance data or functions).

Отсюда логика опции Eclipse.

3. Оригинальный плакат также спрашивает: & quot;Pointing out a method as static, I suppose is showing that you don't use any instance variables therefore could be moved to a utils style class?& Quot; Это очень хороший момент. Иногда такое изменение дизайна обозначается предупреждением.

Это очень полезная опция, которую я лично включил бы, если бы я использовал Eclipse и программировал на Java.

6

я полагаю, что она немного лучше, поскольку в коде не требуется динамическая диспетчеризация в зависимости от типа.

Однако гораздо более сильный аргумент против рефакторинга в статические методы заключается в том, что в настоящее время использование статического кода считается плохой практикой. Статические методы / переменные плохо интегрируются в объектно-ориентированный язык, а также трудно тестируются должным образом. По этой причине некоторые новые языки вообще отказываются от концепции статических методов / переменных или пытаются внедрить ее в язык таким образом, который лучше работает с ОО (например, Objects in Scala).

В большинстве случаев вам нужны статические методы для реализации функций, которые используют только параметры в качестве входных данных, и создают выходные данные, используя их (например, вспомогательные / вспомогательные функции). В современных языках существует концепция функций первого класса, которая допускает это, поэтому статический не нужен Java 8 будет иметь встроенные лямбда-выражения, поэтому мы уже движемся в этом направлении.

Этоprivate static методы, так что вам не нужно будет насмехаться над ними Blundell
Статические методы легко смоделировать, если вы используете мощную инфраструктуру, такую какJMockit, PowerMock, или жеGroovy.
Замечание о тестируемости, вероятно, не было направлено непосредственно на статический метод, но статические методы гораздо труднее подделать, поэтому они усложняют тестирование методов, вызывающих статические методы.
Статические методы тривиальны для тестирования (если они самодостаточны - особенно чистые функции, которые являются основной целью статического метода). В этом случае концепции ОО нечего предложить. Кроме того, концепция первоклассной функции имеет очень мало общего с концепцией статического метода. Если вам когда-нибудь понадобится функция первого класса, которая выполняет работу существующего статического метода, для ее реализации потребуется несколько символов.
129

когда вы пишете метод, вы выполняете контракт в заданной области. Чем уже область действия, тем меньше вероятность, что вы напишите ошибку.

Когда метод является статическим, вы не можете получить доступ к нестатическим элементам; следовательно, ваш кругозор уже. Так что, если вам не нужноand will never need (even in subclasses) нестатические члены для выполнения вашего контракта, зачем предоставлять доступ к этим полям вашему методу? Объявление методаstatic в этом случае компилятор разрешит проверять, не используете ли вы элементы, которые вы не собираетесь использовать.

И более того, это поможет людям, читающим ваш код, понять природу контракта.

Вот почему считается хорошим объявить методstatic когда он фактически выполняет статический контракт.

В некоторых случаях ваш метод означает только что-то, относящееся к экземпляру вашего класса, и бывает, что его реализация фактически не использует какое-либо нестатическое поле или экземпляр. В таких случаях вы бы не отметили методstatic.

Примеры того, где вы не будете использоватьstatic ключевое слово:

An extension hook which does nothing (but could do something with instance data in a subclass) A very simple default behavior meant to be customisable in a subclass. Event handler implementation: implementation will vary with the class of the event handler but will not use any property of the event handler instance.
Кроме того, вам не нужно возиться с получением экземпляра только для вызова независимой, автономной функции.
@PetrMensik Еслиprivate метод может быть объявлен статическим, то почти всегдаshould быть. Для любого другого уровня доступа есть другие факторы, такие как динамическая диспетчеризация.
Поэтому в других мирах любой метод, который не использует переменные экземпляра, должен быть объявлен как статический? Я всегда думал, что методы должны быть статическими, только если это желательно (например, методы utitility).
@JamesPoulson Я имею в виду динамическую отправку методов, то, что происходит во время выполненияobject.method() выбрать метод для вызова.
+1 Речь идет о минимизации возможностей выстрелить себе в ногу и уменьшении того, сколько вам нужно знать, чтобы понять метод.
13

static методstatic потому что вы явно заявляете, что метод не полагается ни на какой экземпляр включающего класса только потому, что ему это не нужно. Так что Eclipse предупреждает, как указано в документации:

When enabled, the compiler will issue an error or a warning for methods which are private or final and which refer only to static members.

Если вам не нужна какая-либо переменная экземпляра, а ваш метод является закрытым (не может быть вызван извне) или окончательным (не может быть переопределен), то нет никаких оснований считать, что это обычный метод, а не статический. Статический метод более безопасен даже потому, что вам разрешено делать с ним меньше вещей (ему не нужен ни один экземпляр, у вас нет никаких неявныхthis объект).

1

Prefer Static Over Virtual If you don't need to access an object's fields, make your method static. Invocations will be about 15%-20% faster. It's also good practice, because you can tell from the method signature that calling the method can't alter the object's state.

http://developer.android.com/training/articles/perf-tips.html#PreferStatic

"то, что вызов метода не может изменить состояние объекта"; - невероятно вводит в заблуждение. Я не знаю о вас, но я определенно считаю, что статические атрибуты класса являются частью состояния объекта.
1

Я предполагаю, что это основной аспект создания статического метода.

Вы также спросили о производительности:

Там может быть небольшое увеличение производительности, потому что вызов статического метода не нуждается в неявном «этом» ссылка как параметр.

Однако это влияние на производительность действительно незначительно. Следовательно, все дело в объеме.

0

Method can be static

When enabled, the compiler will issue an error or a warning for methods which are private or final and which refer only to static members

Я думаю, что это в значительной степени говорит обо всем. Если метод является закрытым и окончательным и ссылается только на статические члены, рассматриваемый метод также может быть объявлен как статический, и тем самым становится очевидным, что мы намереваемся получить доступ только к статическому контенту из него.

Честно говоря, я не думаю, что за этим стоит какая-то таинственная причина.

-2

которые вы можете объявить как статические, это те, которые не требуют инстанцирования, такие как

public class MyClass
{
    public static string InvertText(string text)
    {
        return text.Invert();
    }
}

Что вы можете затем взамен вызывать в любом другом классе без создания экземпляра этого класса.

public class MyClassTwo
{
    public void DoSomething()
    {
        var text = "hello world";
        Console.Write(MyClass.InvertText(text));
    }
}

... Но это то, что вы, вероятно, уже знаете. Он не дает вам никаких реальных преимуществ, за исключением того, что делает более ясным, что метод не использует какие-либо переменные экземпляра.

Другими словами, вы можете наиболее безопасно просто отключить его полностью. Если вы знаете, что никогда не будете использовать метод в других классах (в этом случае он должен быть просто закрытым), вам вообще не нужно, чтобы он был статическим.

Действительно, кажется, я забыл «статичный» из метода InvertText. И это пример, основанный на C #
Что это за язык? Этот пример компилируется? Здесь нет ничего статичного.
0

ался сравнить их, что оказалось не так просто:Цикл Java становится медленнее после некоторых запусков / ошибки JIT?

Я, наконец, использовал Caliper, и результаты те же, что и при тестировании вручную:

There is no measurable difference for static/dynamic calls. По крайней мере, не для Linux / AMD64 / Java7.

Результаты суппорта здесь:https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName,scenario.vmSpec.options.CMSLargeCoalSurplusPercent,scenario.vmSpec.options.CMSLargeSplitSurplusPercent,scenario.vmSpec. options.CMSSmallCoalSurplusPercent, scenario.vmSpec.options.CMSSmallSplitSurplusPercent, scenario.vmSpec.options.FLSLargestBlockCoalesceProximity, scenario.vmSpec.options.G1ConcMarkStepDurationMillis

и мои собственные результаты:

Static: 352 ms
Dynamic: 353 ms
Static: 348 ms
Dynamic: 349 ms
Static: 349 ms
Dynamic: 348 ms
Static: 349 ms
Dynamic: 344 ms

Класс тестирования суппорта был:

public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark {

    public static void main( String [] args ){

        CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args );
    }

    public int timeAddDynamic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addDynamic( 1, i );
        }
        return r;
    }

    public int timeAddStatic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addStatic( 1, i );
        }
        return r;
    }

    public int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

И мой собственный тестовый класс был:

public class TestPerformanceOfStaticVsDynamicCalls {

    private static final int RUNS = 1_000_000_000;

    public static void main( String [] args ) throws Exception{

        new TestPerformanceOfStaticVsDynamicCalls().run();
    }

    private void run(){

        int r=0;
        long start, end;

        for( int loop = 0; loop<10; loop++ ){

            // Benchmark

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addStatic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Static: " + ( end - start ) + " ms" );

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addDynamic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Dynamic: " + ( end - start ) + " ms" );

            // Do something with r to keep compiler happy
            System.out.println( r );

        }

    }

    private int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}
было бы интересно увидеть результаты на различных устройствах и версиях Android Blundell
Да. Я подумал, что вам будет интересно :) Но так как вы создаете программное обеспечение для Android и, возможно, у вас есть устройство Android, подключенное к вашей станции разработчика, я предлагаю вам просто выбрать код, запустить его и поделиться результатами?

Похожие вопросы