121°

Java中的this和super

this关键字

当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是 this

因此,this只能在类中的非静态方法中使用,静态方法静态的代码块中绝对不能出现this,并且this只和特定的对象关联,而不和类关联,同一个类的不同对象不同的this

1、使用this来区分当前对象

Java中为解决变量的命名冲突和不确定性问题,引入关键字this代表其所在方法的当前对象的引用:

  • 构造方法中指该构造器所创建的新对象;
  • 方法中指调用该方法的对象;
  • 在类本身的方法或构造器中引用该类的实例变量(全局变量)和方法。

this只能用在构造器或者方法中,用于获得调用当前的构造器方法的对象引用。可以和任何的对象引用一样来处理这个this对象。

说明:

  • (1)当实例变量和局部变量重名,JAVA平台会按照先局部变量、后实例变量的顺序寻找。即,方法中使用到的变量的寻找规律是先找局部变量,再找实例变量。如果没用找到,将会有一个编译错误而无法通过编译。
  • (2)如果使用this.x,则不会在方法(局部变量)中寻找变量x,而是直接去实例变量中去寻找,如果寻找不到,则会有一个编译错误。
  • (3)在一个方法内,如果没有出现局部变量和实例变量重名的情况下,是否使用this关键字是没有区别的。
  • (4)在同一个类中,Java普通方法的互相调用可以省略this+点号,而直接使用方法名+参数。因为Java编译器会帮我们加上。

2、在构造器中使用this来调用对象本身的其他构造器。

在构造器中使用this([args_list]),可以调用对象本身的其他的构造器。
直接使用this()加上类构造器所需要的参数,就可以调用类本身的其他构造器了。
如果类中有多个其他构造器定义,系统将自动根据this()中的参数个数和类型来找出类中相匹配的构造器。

注意:
在构造器中可以通过this()方式来调用其他的构造器。但在一个构造器中最多只能调用一个其他的构造器。并且,对其他构造器的调用动作必须放在构造器的起始处(也就是构造器的首行),否则编译的时候将会出现错误,另外不能在构造器以外的地方以这种方式调用构造器。

3、 this关键字还有一个重大的作用就是返回类的引用。

如在代码中,可以使用return this来返回某个类的引用。此时,这个this关键字就代表类的名称。

例1. 把this作为参数传递

public class A{
  
    public A(){
    	new B(this).print();
    }
    
    public void print(){
    	System.out.println("From A!");
    }
    
    public static void main(String[] args) {
    	new A();
    }
}
public class B {
    A a;
    public B(A a){
    	this.a = a;
    }
    
    public void print(){
    	a.print();
    	System.out.println("From B!");
    }
}

运行结果:

QQ图片20190602135419.png 在这个例子中,对象A的构造函数中,用new B(this)把对象A自己作为参数传递给了对象B的构造函数。

例2. 注意匿名类和内部类中的中的this。

有时候,我们会用到一些内部类和匿名类,如事件处理。
当在匿名类中出现this时,这个this则指的是匿名类或内部类本身。这时如果我们要使用外部类的方法和变量的话,则应该加上外部类的类名。
如下面这个例子:

public class C {
    int i = 1;
    public C(){
        Thread thread = new Thread(){
            public void run(){
                for(;;){//表示是死循环
                    C.this.run();//调用外部方法run()
                    try {
                        sleep(1000);//睡眠1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };//注意这里有分号;
		thread.start();
    }
    
    public void run(){
        System.out.println("i = " + i);
        i++;
    }

    public static void main(String[] args) throws Exception {
        new C();
    }
}

运行结果: 每一秒产生一个数:1,2,3 …… QQ图片20190602140704.png

如果我们不使用类名.来调用,则调用的是方法本身的run方法,则会变成自己调用自己,变成死循环从而程序报错堆栈溢出

在上面这个例子中, thread 是一个匿名类对象,在它的定义中,它的 run 函数里用到了外部类的 run 函数。这时由于函数同名,直接调用就不行了。这时有两种办法,一种就是把外部的 run 函数换一个名字,但这种办法对于一个开发到中途的应用来说是不可取的。那么就可以用这个例子中的办法用外部类的类名加上 this 引用来说明要调用的是外部类的方法 run。

例3、this关键字最大的作用是,让类的一个方法,访问该类的另一个方法或者属性。

先看一个不好的例子:

public class D {
    public void a(){
        System.out.println("雨女无瓜");
    }

    public void b(){
        D d = new D();
        d.a();
        System.out.println("瓜你屁事");
    }
}

这样不符合逻辑。这就相当于本对象的b方法,需要调用另一个对象的a方法。但是我们都在同一个类中,没必要去再new本身来调用

我们看这个例子:

public class E {
    public void a(){
        System.out.println("雨女无瓜");
    }

    public void b(){
        this.a();
        System.out.println("瓜你屁事");
    }
}

这样就符合逻辑了。自己的a方法,还需要自己的一个b方法,使用this直接调用即可.
java允许同一个对象的方法直接调用该对象的属性或者方法,所以this可以省略。

注意:java中为什么在static中不能使用this关键字

  • Static方法是类方法,先于任何的实例(对象)存在。即Static方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。而this指代的是当前的对象

  • 在方法中定义使用的this关键字,它的值是当前对象的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.

  • 而且,更为重要的是this和super都无法出现在static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象.如果使用的是类来调用而不是对象,

  • 则 this就无法指向合适的对象.所以static 修饰的方法中不能使用this.

super关键字

1、Java中的super是什么

java中的super关键字是一个引用变量,用于引用父类对象。关键字super以继承的概念出现在类中。

2、super关键字作用

  • 1:主要存在于子类方法中,用于指向子类对象中父类对象。
  • 2:访问父类的属性
  • 3:访问父类的函数
  • 4:访问父类的构造函数

3、使用super变量

当派生类和基类具有相同的数据成员时,会发生此情况。
在这种情况下,JVM可能会模糊不清。我们可以使用以下代码片段更清楚地理解它:

class G{
    int num = 120;
}
public class F extends G{
    int num = 180;
	
    void display(){
        System.out.println(super.num);
    }
	
    public static void main(String[] args){
        F f = new F();
        f.display();
    }
}

使用spuer运行结果: super.png 不使用spuer运行结果: super2.png 在上面的例子中,基类和子类都有一个成员num。
我们可以使用super关键字访问父类中的num,如果不使用super则调用的是子类中的num属性

4、使用super方法

当我们要调用父类方法时使用。所以,无论何时,父类和子类都具有相同的命名方法,那么为了解决歧义,我们使用super关键字。
这段代码有助于理解super关键字的使用情况。

class I{
    void message(){
        System.out.println("我是I类的message方法");
    }
}
public class H extends I{
    void message(){
        System.out.println("我是H类的message方法");
    }

    void display(){
        message();
        super.message();
    }

    public static void main(String args[]){
        H h = new H();
        h.display();
    }
}

运行结果: super3.png

在上面的例子中,我们已经看到,如果我们只调用方法message(),那么当前的类message()被调用,但是使用super关键字时,超类的message()被调用。

5、使用super构造函数

super关键字也可以用来访问父类的构造函数
更重要的是,spuer可以根据情况调用参数和非参数构造函数。
以下是解释上述概念的代码片段:

class K{
    public K(){
        System.out.println("老子是K的构造方法");
    }
}
public class J extends K{
    public J() {
        super();
        System.out.println("老子是J的构造方法");
    }

    public static void main(String[] args){
        new J();
    }
}

运行结果: super4.png

在上面的例子中,我们通过子类构造函数使用关键字super调用父类构造函数。

其他要点

子类与其直接父类之间的构造方法存在约束关系,有以下几条重要原则:

  • 按继承关系,构造方法是从顶向下进行调用的。
  • 创建子类的对象时,先执行父类的构造方法,再执行子类的构造方法。
  • 如果子类有构造方法,但子类的构造方法中没有super关键字,则系统默认执行该构造方法时会产生super()代码,即该构造方法会调用父类无参数的构造方法。
  • 对于父类中包含有参数的构造方法,子类可以通过在自己的构造方法中使用super关键字来引用,而且必须是子类构造函数方法中的第一条语句。
  • Java语言中规定当一个类中含有一个或多个有参构造方法,系统提供默认的无参构造方法,所以当父类中定义了多个有参数构造方法时,应考虑写一个无参数的构造方法,以防子类省略super关键字时出现错误。

全部评论: 0

    我有话说: