public boolean contains(Object o) {
for (E x : this)
if (x.equals(o))
return true;
return false;
}
有人能告诉我在这段代码中,“this”到底是什么意思吗?我能否不使用“this”来编写代码?
this
代表调用当前方法的对象。例如,如果您有a.contains(x)
,则在contains
方法内this
将返回与a
引用变量中持有的同一对象的引用。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)
。
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 Monicastruct
具有成员函数,因此C++编译器必须将它们转换为独立的函数;由于它们需要绑定到特定的实例,因此它们必须将该实例作为参数(这必须被实现为指针,因为C没有引用,并且我认为直到this
的语法最终确定之后才添加了引用)。最终看起来像这样。 - Justin Time - Reinstate Monicathis
作为参数传递。这里有一个解释(https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.1),说明为什么存在这个特性:允许注释 this
。 - biziclopthis
是包含您的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
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 ofIterable
, then the translation is as follows.If the type of
Expression
is a subtype ofIterable<X>
for some type argumentX
, then letI
be the typejava.util.Iterator<X>
; otherwise, letI
be the raw typeIterator
.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用户提供迭代内部集合的能力,同时隐藏实际实现。
我可以不使用这个接口吗?如何做到?
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'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()
,如果在可迭代容器中相对于当前位置有另一个对象,则返回true
;next()
返回下一个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);
}
}
方法是在类
中定义的,而不是在对象
中定义的。
但它们通常是从对象
中调用的。
方法 - 正如它们在类
中定义的那样 - 事先不知道哪个对象将调用它们。
因此,有一种机制(由隐藏参数this
实现),当对象调用方法时,它会秘密地将自身的地址传递给参数this
。
(在其他编程语言中可能使用其他名称,如Me
或self
。)
我会为您列出以下几点:
当我们创建一个类的新实例时,非静态方法和成员变量都是其一部分。我们使用 .
运算符来访问这些方法和字段。
所有非静态方法或成员字段都可以访问 this
。关键字 this
简单地是对当前执行该方法的对象的引用。
任何实现了 Iterable
接口的类都可以与增强的 For-Loop
一起使用。
增强型 for 循环使用如下语法
for (Object object : objectOfIterableType)
如果实现 Iterable
接口的类是参数化的,则假设它的类型为 E
,则需要在代码中进行相应操作。
for (E x : this)
this
关键字表示的类型为E的项目集合中的每个项目执行。在每次迭代中,x
将表示来自这些包含项目的项目。
Iterable<E>
类型的东西。在这种情况下,您当前的实例(在#contains
方法期间为this
)是一个Iterable<E>
类型的实例。 - RogueE x : ...
循环的作用,以及this
指的是什么(如果你理解了代码,应该就能明白如何不使用this
重写它)。 - Bernhard Barker