Каковы различия и преимущества методов уровня класса в Objective-C по сравнению с Java

#java #objective-c #class-method

#java #objective-c #класс-метод

Вопрос:

Например, я знаю, что методы класса Objective-C могут быть переопределены, а Java — нет.

В чем преимущество этого и какие существуют другие различия?

Комментарии:

1. вы можете «затенить» метод в Java. Код в байт-коде вызывает точный метод класса. Вы не можете переопределить, но вы все еще можете вызвать статический метод суперкласса.

2. @bestsss как в class A{static void a(){}} class B extends A{ static void a(){A.a();}} ?

3. да. статические методы имеют абсолютно нулевой контекст (кроме вызывающего класса и текущего потока, но это все). Я имею в виду во время выполнения / байт-коде.

Ответ №1:

В двух словах, статические методы в Java — это просто функции, которые прикреплены к классу. Они не работают как методы экземпляра в том смысле, что вы не можете использовать this или super. Они фактически не имеют реального представления о том, что они находятся в классе.

Однако методы класса Objective-C сильно отличаются. Они точно такие же, как методы экземпляра, за исключением класса. Это не слишком удивительно, учитывая, что классы являются объектами в Obj-C. Как таковые, они проходят через все ту же динамическую отправку, вы можете использовать self для доступа к другим методам класса, вы можете использовать super для вызова методов класса суперкласса. Это обеспечивает гораздо большую гибкость, поскольку вы можете выполнять все те же действия с методами класса, что и с методами экземпляра, такими как обмен сообщениями с нулевым значением, перебор методов и т.д.

Комментарии:

1. Классы также являются объектами в java. Также я не согласен с гибкостью. Вы также можете вызвать статический метод суперкласса в java. Я не вижу в этом пользы, поскольку это сбивает с толку. Обычно то, что я хочу от статических методов, — это быть быстрыми и встроенными.

2. Ну, классы — это объекты, но не совсем так, как в Obj-C. В Obj-C класс имеет свой собственный метакласс, который относится к классу, поскольку класс является объектом, т. Е. метакласс содержит список методов для класса и суперметакласс этого класса. Также вы можете вызвать статический метод суперкласса в Java, но это прерывается, если вы меняете иерархию классов и используете механизм, отличный от стандартного вызова метода, в отличие от Obj-C, где он использует точно такой же механизм. Если вы хотите быстрые встроенные вызовы в Obj-C, используйте прямые функции C и избегайте динамической отправки.

3. Также стоит отметить конкретное преимущество гибкости. Такой метод, как [NSString stringWithFormat:@»foo»], является просто удобным методом для выполнения [[[NSString alloc] initWithFormat:@»foo»] автоматического выпуска]. Но если бы это было реализовано подобным образом, и вы добавили NSString в подкласс, тогда [myString stringWithFormat:@»foo»] все равно возвращал бы NSString, а не экземпляр myString. Как таковой, он реализован как [[[self alloc] initWithFormat:@»foo»] autorelease], так что сообщения отправляются в правильный класс.

4. @Martin, я понимаю нарушение «иерархии», в java метод фактически не знает, к какому классу они принадлежат. На самом деле, это можно сделать, динамически разрешив текущий класс, взяв суперкласс и задействовав тот же метод, но это требует огромного количества размышлений (и это скучно, но это может выглядеть как invokeSuper()). Часть initWithString просто вызывает другой c-tor в java (myString), хотя для этого требуется, чтобы подклассы вводили c-tor. Так что пример, вероятно, не самый лучший.

5. Хорошо, поскольку пример Дэниела, я могу сказать, что он может вызывать правильную версию переопределенного метода. Это единственное преимущество? Или есть другие?

Ответ №2:

Ответ Марка Пилкингтона правильный. Вот конкретный пример, иллюстрирующий, что вы можете делать с методами класса Objective-C, но не со статическими методами Java.

Objective-C

 @interface Parent : NSObject
  (int)foo;
  (int)bar;
- (void)printMyFoo;
@end

@interface Child : Parent
  (int)bar; // Override bar only.
@end

@implementation Parent
  (int)foo {
    return [self bar];
}

  (int)bar {
    return 0;
}

- (void)printMyFoo {
    NSLog(@"%d", [[self class] foo]);
}
@end

@implementation Child
  (int)bar {
    return 1;
}
@end
  

Теперь, если вы вызовете printMyFoo экземпляр родительского и дочернего, вы получите разные результаты, потому что [Parent foo] динамически отправляет bar вызов во время выполнения:

 id parent = [[Parent alloc] init];
id child = [[Child alloc] init];
[parent printMyFoo]; // -> 0
[child printMyFoo];  // -> 1
  

Java

 class Parent {
    static int foo() { return bar(); }
    static int bar() { return 0; }
    void printMyFoo() { System.out.println(foo()); }
}

class Child extends Parent {
    static int bar() { return 1; }
}
  

Теперь, если вы вызываете printMyFoo() родительский и дочерний экземпляры, они оба будут печатать одно и то же, потому что даже для дочернего, Parent.foo() вызывает Parent.bar() вместо Child.bar() :

 Parent parent = new Parent();
Child child = new Child();
parent.printMyFoo(); // -> 0
child.printMyFoo();  // -> 0
  

Комментарии:

1. [Child foo] == 1 поскольку сообщение отправляется на Child объект класса, поэтому ссылка на self внутри foo является Child объектом класса.

Ответ №3:

Вот что говорится в документации Java по Oracle (первоначально Sun) о переменных и методах класса:http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html