Java中的this与super

这篇说一下容易混淆的两个关键字:thissuper.

this

简单的介绍

先看看<Java编程思想>上面的解释:

this关键字只能在方法内部使用,表示对"调用方法的那个对象"的引用.this的用法和其他对象引用并无不同.但要注意,如果在方法内部调用同一个类中的另一个方法,就不必使用this,直接调用即可.当前方法中的this引用会自动应用于同一个类中的其他方法.

也就是说,this用来指向同一个类的东西.

构造器中的this

各种代码中,this最多的地方就是构造器了,我们在使用IDE自动生成的时候就可以看到这样的代码:

class SuperClass {    
    //4个变量
    private int id;
    private int number;
    private int load;
    private String name;
    
    //构造器
    SuperClass(int id, int number, int load, String name){
        this.id= id;
        this.number = number;
        this.load = load;
        this.name = name;      
     }
}

 this后面的变量是类中定义的变量,等号后面的方法传入的参数,解释一下就是,这个对象的这个变量等于(被)参数传入的这个变量(赋值).

再来看看稍微复杂一点的,其中加入了用来测试的输出语句:

    SuperClass(int id, String name){                        //构造器1
        this.id = id;
        this.name = name;
        System.out.println("SuperClass 2个参数的构造器.");
    }

    SuperClass(int id, int number, int load, String name){  //构造器2
        this(id, name);
        this.number = number;
        this.load = load;
        System.out.println("SuperClass 4个参数的构造器.");
    }

    SuperClass(int id, int number, int load){               //构造器3
        this(id, number, load, null);
        System.out.println("SuperClass 3个参数的构造器1.");
    }

     SuperClass(int id, int number, String name){           //构造器4
        this(id, number, 0, name);
        System.out.println("SuperClass 3个参数的构造器2.");
    }

现在我们要创建一个3个参数的SuperClass对象,会输出什么呢?实际操作一下看看: 

     public static void main(String[] args) {
        SuperClass sc = new SuperClass(1, 2, 3);
    }

 结果:

    SuperClass 2个参数的构造器.
    SuperClass 4个参数的构造器.
    SuperClass 3个参数的构造器1.

通俗的解释一下就是,传入的参数是(int, int, int),于是就寻找方法签名相同的方法,发现构造器3相同,就执行构造器3.构造器3中调用了这个对象(this)的四个参数的构造器(构造器2) ,构造器2中又调用了这个对象(this)中的两个参数的构造器(构造器1).

方法签名

 方法签名是一个方法的方法名,传入参数的类型构成的,方法签名一样的方法在一个类中只能存在一个,比如上面的几个构造器,而下面的方法不能存在于同一个类中:

    public void sign(int first, int second, String third){}

    public void sign(int a, int b, String c){}

看起来传入参数的名字是不同的,但是是不能共存在一个类中的. 

那跟返回值有没有关系,答案是没有,比如下面的方法也是不允许共存在同一个类中的:

    public void sign(int first, int second, String third){}

    public int sign(int first, int second, String third){ return 1;}

这与方法重载关系很大,首先想想我们使用的输出语句:

    System.out.println();

它好像什么都能输出:给它一个小数,整数,字符,甚至是对象都可以,就是因为它有很多个重载版本:首先判断传入的参数(输出的内容)是什么类型,再调用方法签名(println+参数类型)符合的方法, 我们来看看这个方法有多少个重载版本:

在这条语句中,out是System类中的一个PrintStream类型常量:

    public final static PrintStream out = null;

println()位于java.io.PrintStream中. 

    public void println() {}
    public void println(boolean x) {}
    public void println(char x) {}
    public void println(int x) {}
    public void println(long x) {}
    public void println(float x) {}
    public void println(char x[]) {}
    public void println(String x) {}
    public void println(Object x) {}

回到构造器 

那么再来看看下面这个构造器可以不可以:

    SuperClass(int id, int number, int load){
        System.out.println("SuperClass 3个参数的构造器1.");
        this(id, number, load, null);
    }

答案是不可以,因为Java中规定this()调用本类构造器的语句在构造器中必须位于第一条语句.具体原因可以看看下面的代码:

    class SubClass extends SuperClass{
        SubClass(int id, int number, int load, String name){
            this.load = load;
            this.name = name;
            System.out.println("SubClass 4个参数的构造器.");
        }

        SubClass(int id, int number){
            super(id, number, null);
            System.out.println("SubClass 2个参数的构造器.");
        }

        public static void main(String[] args){
            new SubClass(1, 2, 3, "1");
        }
    }

运行结果是: 

    SuperClass 无参构造器.
    SubClass 4个参数的构造器.

发现第一行出现的是:SuperClass.., 并没有执行另一个构造器,即使已经使用两个this语句对另一个构造器未指定的变量进行了赋值.再来看看加了this的情况:

    SubClass(int id, int number, int load, String name){
        this(id, number);
        this.load = load;
        this.name = name;
        System.out.println("SubClass 4个参数的构造器.");
    }

    SubClass(int id, int number){
        super(id, number, null);
        System.out.println("SubClass 2个参数的构造器.");
    }

    public static void main(String[] args) {
        new SubClass(1, 2, 3, "1");
    }
    

 运行结果:

    SuperClass 2个参数的构造器.
    SuperClass 4个参数的构造器.
    SuperClass 3个参数的构造器2.
    SubClass 2个参数的构造器.
    SubClass 4个参数的构造器.

可以看到这次调用了SubClass中两个参数的构造器, 所以可以说明,如果未显式的指定this,默认就会走父类中的逻辑,也就是super.也就是说会自动在构造器中第一行加入super().

方法中的this

有了上面的铺垫其实要说的内容已经比较少了.需要指出的就是,方法中this可以放在任意位置,不像构造器严格限制在第一条语句,下面的代码就是合法的:

    int out(){ 
        return 1 ;
    }

    int otherOut(){ 
        int i = 100;
        return this.out() + i;
    }

当然,都在同一个类中,也就不用加这个this了:

    int out(){ 
        return 1 ;
    }

    int otherOut(){ 
        int i = 100;
        return out() + i;
    }

super

接下来来说说super.super用来指向离自己最近的父类的东西.

构造器

来看看下面的两个构造器:

class SuperClass{
    SuperClass(){
        System.out.println("SuperClass 无参构造器.");
    }
}

class SubClass extends SuperClass{
    SubClass(){
        System.out.println("SubClass无参构造器.");
    }
}

public class ThisAndSuper{
    public static void main(String[] args){
        new SubClass();
    }
}

运行结果:

    SuperClass 无参构造器.
    SubClass 无参构造器.

这里在子类构造器中隐式的加入了一行代码:

    super();

下面来看看有参构造器:

 SuperClass(int id, int number, int load, String name){
        this.id = id;
        this.name = name;
        this.number = number;
        this.load = load;
    }


  SubClass(int id, int number, int load, int gen, String name){
        super(id, number, load, name);
        this.gen = gen;
    }

这么做的前提是,父类确实存在这样的构造器,如果不存在就会报错. 

这么做也是可以的 :

class SuperClass{
    int id;
    int number;
    int load;
    String name;
    SuperClass(){}
}

class SubClass extends SuperClass{
    private int gen;
    SubClass(int id, int number, int load, int gen, String name){
        super.id = id;
        super.number = number;
        super.name = name;
        super.load = load;
        this.gen = gen;
    }
}

这种情况下需要有默认无参构造器,如果没有声明其它有参构造器,就没必要写出来了,此时系统默认提供一个无参构造器.但是如果声明了有参构造器,那么就需要显式的把默认无参构造器写出来,因为你写的任何有参构造器都会覆盖掉系统默认提供的无参构造器.

根据前面this的介绍,这条语句在构造器中也是只能存在于第一条语句. 下面再看看有参数构造器的情况:

    SuperClass(int id, String name){
        this.id = id;
        this.name = name;
        System.out.println("SuperClass 2个参数的构造器.");
    }

        
        SubClass(int id, int number){
        super(id, number, null);
        System.out.println("SubClass 2个参数的构造器.");
    }

测试类main()中创建一个SubClass对象,可以看到如下结果: 

    SuperClass 2个参数的构造器.
    SubClass 2个参数的构造器.

可知子类构造器中的super确实调用了父类对应的构造器,至于编译器怎么知道的super()中是哪个构造器,还是方法签名的功劳. 需要注意的是,如果子类有参构造器没有显式的继承父类的构造器,会自动在第一行加上super().

方法 

先来看看下面的代码:

class SuperClass{
    private int id;
    private int number;
    private int load;
    private String name;
    SuperClass(int id, int number, int load, String name){
        this.id = id;
        this.name = name;
        this.number = number;
        this.load = load;
    }
    @Override
    public String toString() {
        return id+ "," + name +"," + number + "," + load;
    }
}

class SubClass extends SuperClass{
    private int gen;
    SubClass(int id, int number, int load, int gen, String name){
        super(id,  number,  load,  name);
        this.gen = gen;
    }
    @Override
    public String toString() {
        return super.toString() + "," + gen;
    }
}

然后在测试类中编写如下语句: 

    public static void main(String[] args) {
        SubClass sc = new SubClass(1, 2, 3, 4, "name");
        System.out.println(sc);
    }

运行后可以得到如下结果:

    1,2,3,name,4

 

但是如果父类中不重写toString(),再运行会怎样? 

    keyword.SubClass@6d6f6e28,4

 看起来像是Object默认的toString().

用ctrl+alt+H,同时鼠标点击子类的toString(),可以看到方法调用层次(也就是从这里到最根部都调用了什么方法),这里先看看父类有toString()的调用层次: 

可以看到是父类的toString(),再看看父类没有重写toString()的调用层次:

也就是说直接重写了Object的toString().

其它

这里说一点this与super的一些注意事项

1.this()与super()不能同时的出现在同一个构造器中.

2.this()与super()必须都出现在构造方法的第一条语句.

3.this是调用本类中的方法,super是调用父类中的方法.

4.static环境中不可以使用this与super,包括static变量,static方法,static块.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值