this关键字

this可以算是Java里面比较复杂的关键字,因为this的使用形式上决定了它的灵活性,在程序里面使用this可以实现以下三类结构的描述:
1.当前类中的属性:this.属性;
2.当前类中的方法(构造方法、普通方法):this()、this.方法名称();
3.描述当前对象;

this调用本类属性(使用this调用当前类中属性)

通过现在的分析可以发现,利用构造方法或者是setter方法都可以进行类中的属性的赋值,但是在进行赋值的时候,之前采用的是如下的定义形式:

class Person {
    private String name ;
    private int age ;
    public Person(String n,int a) {
        name = n ;
        age = a ;
    }
    public void tell() {
        System.out.println("姓名:" + name + "、年龄:" + age) ;
    }
    // setter、getter略
}

public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc",39) ;
        per.tell() ;
    }
}

D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
姓名:lhc、年龄:39

但是这个时候在构造方法定义的过程之中会发现有一点点的问题:

    public Person(String n,int a) {
        name = n ;
        age = a ;
    }

这个问题出现在参数名称上,可以发现此时构造方法中两个参数的目的是为了类中的name或age属性初始化,但是现在却发现此时的代码n和a参数名称不好。如果说现在将构造方法中的参数名称修改为name、age,则发现无法进行属性的正确设置:

    public Person(String name,int age) {
        name = name ;
        age = age ;
    }

D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
姓名:null、年龄:0

在Java程序之中,“{}”是作为一个结构体的边界符,那么在程序里面当进行变量(参数、属性都称为变量)使用的时候都会以“{}”作为一个查找边界,所以按照就近取用的原则,此时的构造方法并没有能够访问类中的属性,所以此时为了明确标记出类中的属性与参数的区别,往往会在属性前追加一个“this”,表示本类属性。

class Person {
    private String name ;
    private int age ;
    public Person(String name,int age) {
        this.name = name ;
        this.age = age ;
    }
    public void tell() {
        System.out.println("姓名:" + name + "、年龄:" + age) ;
    }
    // setter、getter略
}

public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc",39) ;
        per.tell() ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
姓名:lhc、年龄:39

在你以后所编写的程序代码之中,只要是访问本类中属性的时候,请一定要加上“this”实现访问。

class Person {
    private String name ;
    private int age ;
    public Person(String name,int age) {
        this.name = name ;
        this.age = age ;
    }
    public void tell() {
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
    // setter、getter略
}

以前吃过亏,所以 只要是访问本类中属性的时候,请一定要加上“this”实现访问
this调用本类方法

除了调用属性之外,this也可以实现方法的调用,但是对于方法的调用就必须考虑构造与普通方法。
1.构造方法调用(this()):使用关键字new实例化对象的时候才会调用构造方法;
2.普通方法调用(this.方法名称()):实例化对象产生之后就可以调用普通方法。

范例:调用类中的普通方法

class Person {
    private String name ;
    private int age ;
    public Person(String name,int age) {
        this.setName(name) ;
        setAge(age) ;  // 加与不加都表示本类方法
    }
    public void tell() {
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
    public void setName(String name) {
        this.name = name ;
    }
    public void setAge(int age) {
        this.age = age ;
    }
    public String getName(){
        return this.name ;
    }
    public int getAge() {
        return this.age ;
    }
}

public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc",39) ;
        per.tell() ;
    }
}

D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
姓名:lhc、年龄:39

除了普通的方法调用之外,还需要进行构造方法的调用,对于构造方法的调用,肯定是要放在构造方法中执行。现在假设说类中一共定义有三个构造方法,但是要求不管调用那个构造方法,都执行一行输出语句“一个新的Person类的对象实例化”。

传统做法实现:

class Person {
    private String name ;
    private int age ;
    public Person() {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
    }
    public Person(String name) {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
        this.name = name ;
    }
    public Person(String name,int age) {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
        this.name = name ;
        this.age = age ;
    }
    public void tell() {
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
    // setter、getter略
}

public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc",39) ;
        per.tell() ;
    }
}



D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
*** 一个新的Person类对象实例化了。****
姓名:lhc、年龄:39

D:\fgqjava>

把主类中的年龄参数39去掉,只剩单参,代码修改处如下:
class Person {
    private String name ;
    private int age ;
    public Person() {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
    }
    public Person(String name) {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
        this.name = name ;
    }
    public Person(String name,int age) {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
        this.name = name ;
        this.age = age ;
    }
    public void tell() {
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
    // setter、getter略
}

public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc") ;  //修改之处,去掉年龄参数39,只剩单参
        per.tell() ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
*** 一个新的Person类对象实例化了。****
姓名:lhc、年龄:0

D:\fgqjava>

System.out.println("*** 一个新的Person类对象实例化了。****") ;
this.name = name ;
把上面的代码想象成10行代码,则会出现代码重复。
如果要想评价一个代码的好坏:
代码结构可以重用,提供的是一个中间独立的支持
我们的目标是:没有重复代码。

利用 this() 构造调用优化

class Person {
    private String name ;
    private int age ;
    public Person() {
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
    }
    public Person(String name) {
        this() ;  // 调用本类无参构造
        this.name = name ;
    }
    public Person(String name,int age) {
        this(name) ;  // 调用本类单参构造
        this.age = age ;
    }
    public void tell() {
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
    // setter、getter略
}

public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc") ;  // 使用单参
        per.tell() ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
*** 一个新的Person类对象实例化了。****
姓名:lhc、年龄:0

代码与传统方法比较,代码减少了很多
主类中使用多参:
... ...
public class JavaDemo {
    public static void main(String args[]) {
        Person per = new Person("lhc",10) ;  // 使用多参
        per.tell() ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
*** 一个新的Person类对象实例化了。****
姓名:lhc、年龄:10

对于本类构造方法的互相调用需要注意以下几点重要问题:
1.构造方法必须在实例化新对象的时候调用,所以“this()”的语句只允许放在构造方法的首行。
2.构造方法互相调用时请保留有程序的出口,别形成死循环。

分析问题1
原来:
    public Person(String name) {
        this() ;  // 调用本类无参构造
        this.name = name ;
    }
不放在首行,代码如下,会报错:
    public Person(String name) {
      this.name = name ;
        this() ;  // 调用本类无参构造
    }

原来的普通方法:
    public void tell() {
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
修改为如下代码,会报错:
    public void tell() {
      this() ;  // 调用本类无参构造
        System.out.println("姓名:" + this.name + "、年龄:" + this.age) ;
    }
“this()”的语句必须且只能放在构造方法的首行,不能放在普通方法中。


分析问题2
    public Person() {
        this("haha",11) ;  // 构造方法,且是首行,但是
        System.out.println("*** 一个新的Person类对象实例化了。****") ;
    }
    public Person(String name) {
        this() ;  // 调用本类无参构造
        this.name = name ;
    }
    public Person(String name,int age) {
        this(name) ;  // 调用本类单参构造
        this.age = age ;
    }
双参调用单参,单参调用无参,无参里面有双参,死循环。

此时的程序在进行编译的时候将会直接出现错误提示:告诉用户,你出现了构造方法的递归调用。

构造方法互调用案例:
现在要求定义一个描述有员工信息的程序类,该类中提供有:编号、姓名、部门、工资,在这个类之中提供有四个构造方法:
【无参构造】编号定义为1000,姓名定义为无名氏;
【单参构造】传递编号,姓名定义为“新员工”,部门定义为“未定”,工资为0.0;
【三参构造】传递编号、姓名、部门,工资为2500.00;
【四参构造】所有的属性全部进行传递。

范例:进行代码的初期实现

class Emp {
    private long empno ;    // 员工编号
    private String ename ;  // 员工姓名
    private String dept ;   // 部门名称
    private double salary ; // 基本工资
    public Emp() {
        this.empno = 1000 ;
        this.ename = "无名氏" ;
    }
    public Emp(long empno) {
        this.empno = empno ;
        this.ename = "新员工" ;
        this.dept = "未定" ;
    }
    public Emp(long empno,String ename,String dept) {
        this.empno = empno ;
        this.ename = ename ;
        this.dept = dept ;
        this.salary = 2500.00 ;
    }
    public Emp(long empno,String ename,String dept,double salary) {
        this.empno = empno ;
        this.ename = ename ;
        this.dept = dept ;
        this.salary = salary ;
    }
    // setter、getter略
    public String getInfo() {  // 给出一个提示信息
        return "雇员编号:" + this.empno +
               "、雇员姓名:" + this.ename +
               "、所在部门:" + this.dept +
               "、基本工资:" + this.salary;
    }
}

public class JavaDemo {
    public static void main(String args[]) {
        Emp emp = new Emp(7369L,"史密斯","财务部",6500.00) ;
        System.out.println(emp.getInfo()) ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
雇员编号:7369、雇员姓名:史密斯、所在部门:财务部、基本工资:6500.0

此时可以发现代码有重复,所以就可以对Emp类进行简化定义。

主类中调用三参构造:7369L,"史密斯","财务部"
class Emp {
    private long empno ;    // 员工编号
    private String ename ;  // 员工姓名
    private String dept ;   // 部门名称
    private double salary ; // 基本工资
    public Emp() {
        this(1000,"无名氏",null,0.0) ;
    }
    public Emp(long empno) {
        this(empno,"新员工","未定",0.0) ;
    }
    public Emp(long empno,String ename,String dept) {
        this(empno,ename,dept,2500.00) ;
    }
    public Emp(long empno,String ename,String dept,double salary) {
        this.empno = empno ;
        this.ename = ename ;
        this.dept = dept ;
        this.salary = salary ;
    }
    // setter、getter略
    public String getInfo() {  // 给出一个提示信息
        return "雇员编号:" + this.empno +
               "、雇员姓名:" + this.ename +
               "、所在部门:" + this.dept +
               "、基本工资:" + this.salary;
    }
}

public class JavaDemo {
    public static void main(String args[]) {
        Emp emp = new Emp(7369L,"史密斯","财务部") ;
        System.out.println(emp.getInfo()) ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
雇员编号:7369、雇员姓名:史密斯、所在部门:财务部、基本工资:2500.0

因为调用的是3参,所以显示salary为2500.00,而不是6500.00

代码的任何位置上都可能有重复,所以消除重复的代码是先期学习中最需要考虑的部分。

综合实战:简单Java类

在以后进行项目的开发与设计的过程之中,简单Java类都将作为一个重要的组成部分存在,慢慢接触到正规的项目设计之后,简单Java类无处不在,并且有可能会产生一系列的变化。所谓的简单Java类指的是可以描述某一类信息的程序类,例如:描述一个人、描述一本书、描述一个部门、描述一个雇员,并且在这个类之中并没有特别复杂的逻辑操作,只作为一种信息存储的媒介存在。

对于简单Java类而言,其核心的开发结构如下:

1.类名称一定要有意义,可以明确的描述某一类事务;
2.类之中的所有属性都必须使用private进行封装,同时封装后的属性必须要提供有setter、getter方法;此处的“必须提供”指的是简单Java类,并非所有的类。
3.类之中可以提供有无数多个构造方法,但是必须要保留有无参构造方法;
4.类之中不允许出现任何的输出语句,所有内容的获取必须返回;
5.【非必须】可以提供有一个获取对象详细信息的方法,暂时将此方法名称定义为getInfo()。

范例:定义一个简单Java类

class Dept {    // 类名称可以明确描述出某类事物
    private long deptno ;
    private String dname ;
    private String loc ;
    public Dept() {}  // 必须提供有“无参”
    public Dept(long deptno,String dname,String loc) {  // 有参构造可以有很多个
        this.deptno = deptno ;
        this.dname = dname ;
        this.loc = loc ;
    }
    public String getInfo() {  // 输出信息,非必须的
        return "【部门信息】部门编号:" + this.deptno + "、部门名称:" + this.dname + "、部门位置:" + this.loc ;
    }
    public void setDeptno(long deptno) {
        this.deptno = deptno ;
    }
    public void setDname(String dname) {
        this.dname = dname ;
    }
    public void setLoc(String loc) {
        this.loc = loc ;
    }
    public long getDeptno() {
        return this.deptno ;
    }
    public String getDname() {
        return this.dname ;
    }
    public String getLoc() {
        return this.loc ;
    }
}
public class JavaDemo {
    public static void main(String args[]) {
        Dept dept = new Dept(10,"技术部","北京") ;
        System.out.println(dept.getInfo()) ;
    }
}


D:\fgqjava>javac JavaDemo.java

D:\fgqjava>java JavaDemo
【部门信息】部门编号:10、部门名称:技术部、部门位置:北京

D:\fgqjava>

这种简单Java类基本上就融合了所有的现在接触到的概念,例如:数据类型划分、类的定义、private封装、构造方法、方法定义、对象实例化。简单Java类是很容易理解的,但是很重要,别到时候写不出来。

衍生出的问题:后续解决

关键字new干了什么事情?
GC如何做的?
为什么有setter和getter?
为什么有无参构造方法?
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容