这段代码中的“this”是什么意思?

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

有人能告诉我在这段代码中,“this”到底是什么意思吗?我能否不使用“this”来编写代码?


3
简单来说,在增强的for循环中,冒号后面的第二个参数是任何Iterable<E>类型的东西。在这种情况下,您当前的实例(在#contains方法期间为this)是一个Iterable<E>类型的实例。 - Rogue
2
可能是Java中"this"的含义是什么?的重复问题。 - Bernhard Barker
6
这里可能有两个问题 - E x : ... 循环的作用,以及 this 指的是什么(如果你理解了代码,应该就能明白如何不使用 this 重写它)。 - Bernhard Barker
1
尴尬。我想将其关闭为重复内容,但是从2010年提出的备选内容没有被接受的答案... :/ . - Stewart
6个回答

22
this代表调用当前方法的对象。例如,如果您有a.contains(x),则在contains方法内this将返回与a引用变量中持有的同一对象的引用。
由于您能够在for-each中使用this,这意味着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.contains(b,x))。

为了避免这种重复,我们可以使contains方法成为static,这将允许通过YourClass.contains(a,x)调用它。但这种方式需要放弃面向对象编程(OOP)的一个基本概念—多态性,因为它在static方法中无法使用。

编译器使用第一种解决方案来解决这个问题,因此它编译我们的方法就像它们被编写了一样(实际上我们确实可以这样编写方法):

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

当我们写 a.contains(x) 时,它被编译为调用 a.contains(a,x)


3
重要的点赞关于将“this”参数包含在参数列表中。不知道你可以这样做。 - Rogue
@Rogue,就像许多其他事情一样,我相信这是Java对C++解决C限制的简化。简而言之,在C++中,编译器基本上将成员函数转换为独立函数,其中this是隐式传递的第一个参数;给定类类型class C { public: void f() {} };和实例C c,编译器将基本上将成员C::f()转换为独立的void C_f(C* const this) {},并将c.f()调用为C_f(&c)。与C++不同,Java似乎允许程序员在参数列表中手动指定this - Justin Time - Reinstate Monica
这是因为原始的C++编译器实际上将C++代码交叉编译成C代码。由于C不允许struct具有成员函数,因此C++编译器必须将它们转换为独立的函数;由于它们需要绑定到特定的实例,因此它们必须将该实例作为参数(这必须被实现为指针,因为C没有引用,并且我认为直到this的语法最终确定之后才添加了引用)。最终看起来像这样 - Justin Time - Reinstate Monica
(名称将比“C :: f”更复杂,但名称混淆与此无关。) - Justin Time - Reinstate Monica
1
哇,我不知道你可以明确地将 this 作为参数传递。这里有一个解释(https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.1),说明为什么存在这个特性:允许注释 this - biziclop

5

this是包含您的contains()方法的类的对象。它指的是执行该方法的那个类的对象。

将其放置在增强型for循环的:之后意味着包含此方法的类必须实现Iterable<E>,因为增强型for循环可用于迭代数组或实现Iterable接口的类的实例。这意味着您的类能够迭代一些 E元素的集合。E可能是一个通用类型参数。

为了在没有this的情况下编写您的方法,您必须提供对某些实现了Iterable<E>的替代对象的引用,但我不认为这样做有意义。


4
这段代码中的this具体是什么意思?
它总是指向当前实例。我假设你的类实现了Iterable<T>接口并重写了它的Iterator<T> iterator()方法。
循环只是增强型for语句的语法糖。根据规范(§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
}
通常,一个类实现Iterable接口,以便向API用户提供迭代内部集合的能力,同时隐藏实际实现。

我可以不使用这个接口吗?如何做到?

  1. 使用您编写的内部迭代器逻辑。
  2. 使用底层集合的实现(如果它存在且适用)。
  3. 选择上述选项之一,并将其重写为标准的for循环。

1

关键字 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'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;
    }
}

任何实现了Iterable接口的东西都有一个方法,可以返回Iterator实例,这个实例被隐式地用于foreach循环来迭代对象中的项目。 Iterator有两个方法: hasNext(),如果在可迭代容器中相对于当前位置有另一个对象,则返回truenext()返回下一个object或抛出NoSuchElementException(如果上一次调用hasNext()返回false)。

以下是一个带有contains方法的Iterable实现的简单示例:

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

0

方法是在中定义的,而不是在对象中定义的。

但它们通常是从对象中调用的。

方法 - 正如它们在中定义的那样 - 事先不知道哪个对象将调用它们


因此,有一种机制(由隐藏参数this实现),当对象调用方法时,它会秘密地将自身的地址传递给参数this

(在其他编程语言中可能使用其他名称,如Meself。)


0

我会为您列出以下几点:

  1. 当我们创建一个类的新实例时,非静态方法和成员变量都是其一部分。我们使用 . 运算符来访问这些方法和字段。

  2. 所有非静态方法或成员字段都可以访问 this。关键字 this 简单地是对当前执行该方法的对象的引用。

  3. 任何实现了 Iterable 接口的类都可以与增强的 For-Loop 一起使用。

  4. 增强型 for 循环使用如下语法

for (Object object : objectOfIterableType)

如果实现 Iterable 接口的类是参数化的,则假设它的类型为 E,则需要在代码中进行相应操作。

    for (E x : this)
  • 这意味着当前类具有可迭代的行为,并且可以在其持有的项目集合上进行迭代。上述语句将针对当前对象所引用的this关键字表示的类型为E的项目集合中的每个项目执行。在每次迭代中,x将表示来自这些包含项目的项目。

  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接