11
 public boolean contains(Object o) {
    for (E x : this)
        if (x.equals(o))
            return true;
    return false;
}

Can someone tell me what excatly means "this" in this code? Can I write it without this and how?

Ana Matijanovic
  • 277
  • 3
  • 13
  • 3
    simply put, the second argument (after `:`) in that enhanced for loop is anything which is an `Iterable`. Your current instance (`this` during the `#contains` method) is an instance of an `Iterable` in this case. – Rogue May 21 '17 at 10:48
  • 2
    Possible duplicate of [What is the meaning of "this" in Java?](http://stackoverflow.com/questions/3728062/what-is-the-meaning-of-this-in-java) – Bernhard Barker May 21 '17 at 16:17
  • 6
    There are possibly 2 questions here - [what the `E x : ...` for-loop does](http://stackoverflow.com/questions/2399590/java-what-does-the-colon-operator-do), and then [what the `this` refers to](http://stackoverflow.com/questions/3728062/what-is-the-meaning-of-this-in-java) (and how to rewrite it without `this`, which should become obvious if you understand the code) – Bernhard Barker May 21 '17 at 16:24
  • 1
    Awkward. I want to close as a duplicate, but the candidate duplicate from 2010 has no accepted answer ... :/ . – Stewart May 21 '17 at 20:45

6 Answers6

22

Here this represents object on which current method was invoked. For instance if you have a.contains(x) then inside contains method this will return reference to same object as held in a reference variable.

Since you ware able to use this in for-each it means that contains method is placed in class which implements Iterable<E> interface because for-each can iterate only over:

  • arrays like String[] array = ...; for(String s : array){...}
  • instances of classes which implement Iterable<E> like List<String> where we can write for(String s : list){...}

To avoid this you can explicitly add to your method parameter of class which contains this method, like

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;
}

but this means you would need to call such method in a way a.contains(a,x) so it needs to repeat a twice (not to mention it can allow us to pass other instance of our class than a like a.contains(b,x)).

To avoid this repetition we can make contains method static which will allow to invoke it via YourClass.contains(a,x). But this way we need to resign from one of basic OOP concepts - polymorphism - since it doesn't work with static methods.

Compiler solves it using first solution, so it compiles our methods like they would be written (and we actually CAN write methods that way) as

public boolean contains(YourClass this, Object o) {
//                      ^^^^^^^^^^^^^^
    ...
}

Then when we write a.contains(x) it is compiled as if we would invoke a.contains(a,x).

Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • 3
    Major upvote about the `this` argument included in the parameter list. Didn't know you could do that – Rogue May 21 '17 at 10:51
  • @Rogue It, like many things, is a Java simplification of a C++ workaround to a C limitation, I believe. Long story short, in C++, the compiler essentially translates member functions into freestanding functions, where `this` is the implicitly-passed first parameter; given class type `class C { public: void f() {} };` and instance `C c`, the compiler will essentially translate member `C::f()` into freestanding `void C_f(C* const this) {}`, and call `c.f()` into `C_f(&c)`. Unlike C++, Java seems to allow the programmer to manually specify `this` in the parameter list. – Justin Time - Reinstate Monica May 21 '17 at 16:41
  • (This is because the original C++ compiler actually cross-compiled C++ code into C code. Since C doesn't allow `struct`s to have member functions, the C++ compiler had to turn them into freestanding functions; since they needed to be tied to a specific instance, they had to take that instance as a parameter (which had to be implemented as a pointer, both because C didn't have references, and because I don't believe references were added to the language until after `this`' syntax was finalised). It ends up looking like [this](http://coliru.stacked-crooked.com/a/791690f6485777a2).) – Justin Time - Reinstate Monica May 21 '17 at 17:05
  • (The names will be more complex than `C::f` turning into `C_f`, though, but name mangling isn't relevant to this.) – Justin Time - Reinstate Monica May 21 '17 at 17:16
  • 1
    Wow, I didn't know you could explicitly pass `this` as a parameter. There is an explanation [here](https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.1) to why this feature exists: to allow the annotation of `this`. – biziclop Jun 05 '17 at 20:20
5

this is a object of the class that contains your contains() method. It refers to the object of that class for which the method is executed.

Putting it after the : of an enhanced for loop means that the class that contains this method must implement Iterable<E>, since the enhanced for loop can be used to iterate over either arrays or instances of classes that implement the Iterable interface. This means your class is able to iterate over some collection of E elements. E is probably a generic type parameter`.

In order to write your method without this, you would have to supply a reference to some alternative object that implements Iterable<E>, but I don't see the point of doing that.

Eran
  • 387,369
  • 54
  • 702
  • 768
4

What exactly means this in this code?

It is always a reference to the current instance. I assume your class implements the Iterable<T> interface and overrides the Iterator<T> iterator() method from it.

The loop is just a syntax sugar for the enhanced for statement. According to the specification (§14.14.2.):

for ({VariableModifier} UnannType VariableDeclaratorId : Expression)
    Statement

The type of the Expression must be Iterable or an array type (§10.1), or a compile-time error occurs.

If the type of Expression is a subtype of Iterable, then the translation is as follows.

If the type of Expression is a subtype of Iterable<X> for some type argument X, then let I be the type java.util.Iterator<X>; otherwise, let I be the raw type Iterator.

The enhanced for statement is equivalent to a basic for statement of the form:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    {VariableModifier} TargetType Identifier = (TargetType) #i.next();
    Statement
}

Usually, a class implements the Iterable to provide to an API user the ability of being allowed to iterate over the internal collection hiding the actual implementation.

Can I write it without this and how?

  1. Use the logic you have written for the inner iterator.
  2. Use the implementation of the underlying collection (if it's and it suits).
  3. Choose one of the options mentioned above and rewrite into a standard for.
Community
  • 1
  • 1
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
1

Keyword this is just a reference to the current object.

Here is a example how can be this used:

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's 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;
    }
}

Anything that implements Iterable interface has method which returns Iterator instance, which is implicitly used by foreach loop to iterate over items hold by object. Iterator has methods hasNext() which returns true, if there is another object in iterable container, relative to current position, and next() which returns next object or throws NoSuchElementException if there is no next object (last invokation of hasNext() has returned false).

Here is a simple example of Iterable implementation with contains methods:

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);
    }
}
matoni
  • 2,479
  • 21
  • 39
0

Methods are defined in classes, not in objects.

But they are (generally) invoked from objects.

Methods - as they are defined in classes - don't know in advance which object will call them.


So there is a mechanism (implemented by a hidden parameter this) by which the object - when calling a method - secretively passes the address of itself to parameter this.

(In other programming languages may be used other names, as Me or self.)

MarianD
  • 13,096
  • 12
  • 42
  • 54
0

I would put it in points for you

  1. When we create a new instance of a class then the non static methods and non static member fields are part of it. We access these methods and fields using . operator.

  2. All the non static method or member fields has access to this. The this keyword simply is a reference to the current object upon which that method is executed upon.

  3. Any class which implements Iterable interface can be used with enhanced For-Loop.

  4. Enhanced for loop uses a syntax

for (Object object : objectOfIterableType)

If the class implementing Iterable interface is parametized, suppose its E. then its what you have to in your code.

    for (E x : this)
  1. It means current class has the behaviour of being iterable and can be iterated on the collection of items it holds. Above statement will be executed for each item in the collection of items of type E represented by by the current object referred by this keyword. In each iteration x will represent an item from those contained items.
nits.kk
  • 5,204
  • 4
  • 33
  • 55