#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