(转)Java类和对象 详解(二)

原文链接 https://blog.csdn.net/wei_zhi/article/details/52750933

上一篇Java类和对象 详解(一)讲解了类和对象的基本概念,定义和使用,以及对象引用传递的初步分析,下面接着来讲其他内容。

一、面向对象的封装性

封装(encapsulation)又叫隐藏实现(Hiding the implementation)。就是只公开代码单元的对外接口,而隐藏其具体实现。比如手机,手机的键盘,屏幕,听筒等,就是其对外接口。你只需要知道如何按键就可以使用手机,而不需要了解手机内部的电路是如何工作的。封装机制就像手机一样只将对外接口暴露,而不需要用户去了解其内部实现。

在研究封装性之前,我们先来看一段代码:

package com.wz.classandobj;

class Book{

    String title;
    double price;

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();
            book.title = "Java开发";
            book.price = -89.9;
            book.getInfo();
        }
}

运行结果:

图书的名称:Java开发 图书的价格:-89.9

以上代码没有任何语法错误,却存在一个业务逻辑的错误,因为图书的价格不能为负数。造成这种情况的的原因在于:对象可以在一个类的外部直接访问属性。
如何解决?我们需要将Book类中的属性设置为对外不可见(只能是本类访问),可以使用private关键字来定义属性。

修改之前的代码如下:

package com.wz.classandobj;

class Book{

    private String title;
    private double price;

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();
            book.title = "Java开发";
            book.price = -89.9;
            book.getInfo();
        }
}

运行:

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
    The field Book.title is not visible
    The field Book.price is not visible

    at com.wz.classandobj.TestDemo.main(TestDemo.java:16)

我们发现,在访问属性的时候,外部的对象无法再直接调用类中的属性了,此时就相当于Book类的属性对外部不可见。

但是,要想让程序可以正常运行,那么必须让外部可以操作Book类的属性。在Java开发中,针对属性有这样的定义,在类中定义的属性都要求使用private声明,如果属性需要被外部所使用,那么按照要求,定义属性相应的setter和getter方法,以Book类中的String title 为例:
(1)setter方法是设置属性内容:

public void setTitle(String t)

主要:有参数。

(2)getter方法是取得属性内容:

public String getTitle()

注意:无参数。

范例:为Book类的封装属性设置setter和getter。

package com.wz.classandobj;

class Book{

    private String title;
    private double price;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book();
            book.setTitle("Java开发"); 
            book.setPrice(-89.9);
            book.getInfo();
        }
}

运行结果:

图书的名称:Java开发 图书的价格:-89.9

发现,图书的价格是负数,需要加入检查业务逻辑错误的代码,可以在setter中增加验证,如果值为正,赋值,否则为默认值0.0:

    public void setPrice(double price) {
        if(price > 0.0){
            this.price = price;
        }
    }

对于数据验证,在Java标准开发中应该由辅助代码完成。在实际开发中,setter往往只是简单的设置属性内容,getter只是简单的取得属性内容。

开发建议:以后在定义类的时候,所有的属性都要编写private封装,封装之后的属性如果需要被外部操作,则编写setter、getter。

二、类中的构造方法

先来看对象的产生格式:

①类名称 ②对象名称 = ③new ④类名称();

①类名称:规定了对象的类型。即:对象可以使用哪些属性和方法都是由类定义的;
②对象名称:如果需要使用对象,需要有一个名称,这是一个唯一的标记;
③new:分配新的堆内存空间;
④类名称():调用了名称和类名称相同的方法,这就是构造方法。

实际上,构造方法一直在被我们调用,但我们并没有去定义它,为什么能够使用呢?这是因为在整个Java开发中,为了保证程序可以正常执行,即便用户没有定义任何构造方法,也会在程序编译后自动为类增加一个没有参数,方法名称与类名称相同,没有返回值的构造方法。

构造方法的定义:方法名称和类名称相同,没有返回值声明。

    //无参,无返回值的构造方法
    public Book() {

    }

如果在Book类中没有定义以上的构造方法,那么也会自动生成一个无参,无返回值的构造方法。

我们再看:

package com.wz.classandobj;

class Book{

    //无参,无返回值的构造方法
    public Book() {
        System.out.println("无参构造方法");
    }

}

public class TestDemo {
        public static void main(String args[]) {
            Book book = null;//声明对象
        }
}

运行,什么也没有打印。
在主方法中加入实例化对象的代码:

public class TestDemo {
        public static void main(String args[]) {
            Book book = null;//声明对象
            book = new Book();//实例化对象
        }
}

运行:

无参构造方法

以上说明,构造方法是在对象使用关键字new实例化的时候被调用

构造方法与普通方法最大的区别是:
构造方法在实例化对象(new)的时候只调用一次,而普通方法是在实例化对象之后可以随意调用多次。

在实际开发中,构造方法的作用是在类对象实例化的时候设置属性的初始化内容,范例如下:

package com.wz.classandobj;

class Book{

    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book = new Book("Java开发",89.9);//设置属性的初始化内容
            book.getInfo();

        }
}

运行结果:

图书的名称:Java开发 图书的价格:89.9

如果一个类中已经明确定义了一个构造方法,则无参构造方法将不会自动生成。而且,一个类之中至少存在一个构造方法。另外,既然构造方法也属于方法,那么构造方法也可以重载,但是由于构造方法的特殊性,所以在构造方法重载时注意其参数的类型及参数的个数即可。

范例如下:

package com.wz.classandobj;

class Book{

    private String title;
    private double price;

    public Book() {
        System.out.println("无参的构造方法");
    }

    public Book(String title) {
        this.title = title;
        System.out.println("有一个参数的构造方法");
    }

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
        System.out.println("有俩个参数的构造方法");
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book1 = new Book();
            book1.getInfo();

            Book book2 = new Book("Java开发");
            book2.getInfo();

            Book book3 = new Book("Java开发",89.9);
            book3.getInfo();

        }
}

运行结果:

无参的构造方法
图书的名称:null 图书的价格:0.0
有一个参数的构造方法
图书的名称:Java开发 图书的价格:0.0
有俩个参数的构造方法
图书的名称:Java开发 图书的价格:89.9

在进行构造方法重载时有一个编写建议:所有重载的构造方法按照参数的个数由多到少,或者是由少到多排列。

我们再来看,如果在类中为属性直接设置默认值,结果会怎样?

package com.wz.classandobj;

class Book{

    private String title = "Android开发";
    private double price = 199.9;

    public Book() {
        System.out.println("无参的构造方法");
    }

    public Book(String title) {
        this.title = title;
        System.out.println("有一个参数的构造方法");
    }

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
        System.out.println("有俩个参数的构造方法");
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            Book book1 = new Book();
            book1.getInfo();

            Book book2 = new Book("Java开发");
            book2.getInfo();

            Book book3 = new Book("Java开发",89.9);
            book3.getInfo();

        }
}

运行结果:

无参的构造方法
图书的名称:Android开发 图书的价格:199.9
有一个参数的构造方法
图书的名称:Java开发 图书的价格:199.9
有俩个参数的构造方法
图书的名称:Java开发 图书的价格:89.9

从上面可以发现:如果在类中为属性直接设置默认值,而且这个默认值是在构造方法执行完后才会设置的,且属性内容为对应数据类型的默认值时才设置类中定义的这个默认值。但是,要注意的是在构造方法没有执行之前,属性内容都是其对应数据类型的默认值。

三、类中的匿名对象

没名字的对象称为匿名对象,对象的名字按照之前的内存关系来讲,在栈内存之中,而对象的具体内容在堆内存之中保存,这样,没有栈内存指向堆内存空间,就是一个匿名对象。

范例:

package com.wz.classandobj;

class Book{

    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
        System.out.println("有俩个参数的构造方法");
    }

    public void getInfo(){
        System.out.println("图书的名称:"+title+" 图书的价格:"+price);
    }
}

public class TestDemo {
        public static void main(String args[]) {
            //匿名对象
            new Book("Java开发",89.9).getInfo();

        }
}

运行结果:

有俩个参数的构造方法
图书的名称:Java开发 图书的价格:89.9

匿名对象由于没有对应的栈内存指向,所以只能使用一次,一次之后就将成为垃圾,并且等待被GC回收释放。

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

推荐阅读更多精彩内容