public boolean contains(Object o) {
for (E x : this)
if (x.equals(o))
return true;
return false;
}
Может ли кто-нибудь сказать мне, что в этом коде означает "this". Могу ли я написать его без этого и как?
public boolean contains(Object o) {
for (E x : this)
if (x.equals(o))
return true;
return false;
}
Может ли кто-нибудь сказать мне, что в этом коде означает "this". Могу ли я написать его без этого и как?
Здесь this
представляет объект, по которому вызывается текущий метод. Например, если у вас есть a.contains(x)
, то внутри contains
метод this
вернет ссылку на тот же объект, что и в ссылочной переменной a
.
Поскольку вы можете использовать this
in for-each, это означает, что метод contains
помещается в класс, который реализует интерфейс Iterable<E>
, потому что for-each может выполнять итерацию только:
String[] array = ...; for(String s : array){...}
Iterable<E>
как List<String>
, где мы можем написать for(String s : list){...}
Чтобы избежать this
, вы можете явно добавить свой параметр метода класса, который содержит этот метод, например
public boolean contains(YourClass yc, Object o) {
//and use that parameter in loop instead of `this`
for (E x : yc)
if (x.equals(o))
return true;
return false;
}
но это означает, что вам нужно будет вызвать такой метод способом a.contains(a,x)
, поэтому ему нужно дважды повторить a
(не говоря уже о том, что это может позволить нам передать другой экземпляр нашего класса, чем a
, как a.contains(b,x)
).
Чтобы избежать этого повторения, мы можем сделать метод contains
static
, который позволит вызвать его через YourClass.contains(a,x)
. Но таким образом нам нужно отказаться от одного из основных понятий ООП - полиморфизма - поскольку он не работает с методами static
.
Компилятор решает его с помощью первого решения, поэтому он компилирует наши методы, как они были бы написаны (и мы на самом деле МОЖИМ писать методы таким образом) как
public boolean contains(YourClass this, Object o) {
// ^^^^^^^^^^^^^^
...
}
Тогда, когда мы пишем a.contains(x)
, он компилируется так, как если бы мы вызывали a.contains(a,x)
.
this
- это объект класса, который содержит ваш метод contains()
. Он ссылается на объект этого класса, для которого выполняется этот метод.
Помещая это после :
расширенного цикла for, означает, что класс, содержащий этот метод, должен реализовывать Iterable<E>
, поскольку расширенный цикл for может использоваться для итерации по массивам или экземплярам классов, которые реализуют Iterable
. Это означает, что ваш класс может выполнять итерацию по некоторой коллекции элементов E
. E
, вероятно, является типичным параметром типа.
Чтобы написать ваш метод без this
, вам нужно будет указать ссылку на какой-либо альтернативный объект, который реализует Iterable<E>
, но я не вижу смысла делать это.
Что именно означает
this
в этом коде?
Это всегда ссылка на текущий экземпляр. Я предполагаю, что ваш класс реализует Iterable<T>
интерфейс и переопределяет метод Iterator<T> iterator()
.
Цикл - это просто синтаксический сахар для расширенного оператора for
. Согласно спецификации (§14.14.2.):
for ({VariableModifier} UnannType VariableDeclaratorId : Expression) Statement
Тип выражения должен быть Iterable или тип массива (§10.1), или возникает ошибка времени компиляции.
Если тип
Expression
является подтипомIterable
, тогда перевод выглядит следующим образом.Если тип
Expression
является подтипомIterable<X>
для некоторого аргумента типаX
, то пустьI
- типjava.util.Iterator<X>
; в противном случае пустьI
будет сырым типомIterator
.Усиленный оператор for эквивалентен основному выражению формы:
for (I #i = Expression.iterator(); #i.hasNext(); ) { {VariableModifier} TargetType Identifier = (TargetType) #i.next(); Statement }
Обычно класс реализует Iterable
, чтобы предоставить пользователю API возможность разрешить итерацию по внутренней коллекции, скрывающей фактическую реализацию.
Могу ли я написать его без этого и как?
for
.Ключевое слово this
- это просто ссылка на текущий объект.
Вот пример, как можно использовать this
:
public class Person {
public final String name;
public Person(String name) {
// name = name;
// which one is an argument, and which one is class field?
// by default, both are reference on argument
// using "this" to access class field
this.name = name;
}
public void copyFields(Person other) {
// current object reference is the same as other object reference
// in other words "this" and "other" are the same instances
// example:
// Person p1 = new Person("a");
// Person p2 = p1; // p2 is now pointing on the same memory address
// // as p1, so both are pointing on the same object
// // stored in memory.
// p1.copyFields(p2);
if (this == other) { // copying from self? useless...
return;
}
this.name = other.name;
}
}
Все, что реализует интерфейс Iterable
, имеет метод, который возвращает экземпляр Iterator
, который неявно используется циклом foreach для перебора элементов, удерживаемых объектом. Итератор
имеет методы hasNext()
, который возвращает true
, если есть другой объект
в итерируемом контейнере относительно текущего положения и next()
, который возвращает
next object
или throws NoSuchElementException
, если нет следующего объекта (последнее обращение hasNext()
вернуло false
).
Вот простой пример реализации Iterable
с помощью методов contains
:
public class Customer extends Person implements Iterable<Item> {
private final List<Item> list = new LinkedList<>();
public final String name;
public Customer(String name) {
this.name = name;
}
public void add(Item item) {
list.add(item);
}
// implementing iterable interface
@Override
public Iterator<Item> iterator() {
return list.iterator();
}
// some contains implementations
public boolean contains1() {
for (Item item : this) { // customer implements Iterable = OK
if (o.equals(item)) {
return true;
}
}
return false;
}
public boolean contains2() {
for (Item item : list) { // list implements Iterable = OK
if (o.equals(item)) {
return true;
}
}
return false;
}
public boolean contains3(Object o) {
for (Iterator<Item> iter = iterator(); iter.hasNext(); ) {
Item item = iter.next();
if (o.equals(item)) {
return true;
}
}
return false;
}
public boolean contains4(Object o) {
for (Iterator<Item> iter = list.iterator(); iter.hasNext(); ) {
Item item = iter.next();
if (o.equals(item)) {
return true;
}
}
return false;
}
public boolean contains5(Object o) {
Iterator<Item> iter = iterator();
while (iter.hasNext()) {
Item item = iter.next();
if (o.equals(item)) {
return true;
}
}
return false;
}
public boolean contains6(Object o) {
Iterator<Item> iter = list.iterator();
while (iter.hasNext()) {
Item item = iter.next();
if (o.equals(item)) {
return true;
}
}
return false;
}
public boolean contains7(Object o) {
return list.contains(o);
}
}
Методы определены в classes
, а не в objects
.
Но они (обычно) вызывается из objects
.
Методы - как они определены в classes
- не знают заранее, какой объект будет их называть.
Итак, существует механизм (реализуемый скрытым параметром this
), с помощью которого объект - при вызове метода - тайно передает адрес себя параметру this
.
(В других языках программирования могут использоваться другие имена, как Me
или self
.)
Я бы поместил его в пункты для вас
Когда мы создаем новый экземпляр класса, то его нестационарные методы и нестатические поля-члены являются его частью. Мы обращаемся к этим методам и полям с помощью оператора .
.
Все поля нестатического метода или члена имеют доступ к this
. Ключевое слово this
просто является ссылкой на текущий объект, по которому этот метод выполняется.
Любой класс, который реализует интерфейс Iterable
, может использоваться с расширенным For-Loop
.
Расширенный цикл for использует синтаксис
for (Object object : objectOfIterableType)
Если класс, реализующий интерфейс Iterable
, параметризован, предположим его E
. то это то, что вам нужно в вашем коде.
for (E x : this)
this
. На каждой итерации x
будет отображаться элемент из содержащихся в нем элементов.