2020年小白升级之路之对象与类

在这里插入图片描述

到目前为止,已经从事 Java 几个月的时间了,虽然还是一个小小白,但真的感觉到如果仅仅靠工作中学习到的东西来提升自己,那真的是太少了,也太缓慢了,而且这个过程本身也是没有一个系统性的道路,但是在工作中确实可以学习到一些实际解决的快速方法,不管是代码逻辑还是规范,还要学习的还有很多很多。

这条小白升级的路也不知道会有多久,但是我会从最基础开始,为自己巩固,也会自己记录。

那么今天来了解一下小白升级路中的《对象与类》,就看看这四个字,再想一想 Java又是面向对象编程,那么关系就越来越靠近了,简单介绍一下面向对象编程的简称 OOP,英文全称Object Oriented Programming。

1.类

​ 类(CLass)是对象的模板或蓝图,在面向对象编程的三大特点中,封装和继承体现在类和类之间;

1.1 封装

​ 在类中,从形式上看,封装是将数据和行为隐藏或包装到类中,这些数据和行为有的属于实例域(对象),还有的属于静态域(类),一般来说,有 static 修饰的Filed(变量,包括属性和方法)属于静态域,不属于实例域,静态域只能由类本身调用,实例域的由对象调用;封装的特性一定程度上的保护了类的隐私性,也防止对象对其他类的随意访问;

1.2 继承

​ 封装是在一个类中出现,而继承是在两个类之间,当子类继承父类后,也获取到了父类的全部属性和方法,而此时子类也可以拥有自己的属性和方法,继承的出现让类的扩展性更加强大了,在 Java 中,所有类都有一个父类 Object,也继承了 Object 的属性和方法;子类继承父类,是使用(子 extends 父)代表继承;

2.对象

2.1 对象和类的区别

​ 对象是类的实例化,具体化的形式;举个例:手机类(包括摄像头(属性),通讯录(属性),还有打电话功能(方法)),手机的具体化对象是小米 8,此时摄像头属性为 2000 万,通信录有 10 个电话号码,打电话给具体的某个人。这个例子中,手机类是类,是对象的模板,而小米 8 是实例化,可以更具体的按照模板去给定特定的数据或者方式。

​ 一个类可以对应多个对象,每个对象也存在差异性。比如:小米八,华为 40,都有摄像头,通讯录,打电话功能,但是具体的参数确实不同的;

2.2 对象的初始化

​ 从上面例子,大概的认识了类和对象区别,那接下来将会通过 Date类作为例子说一下对象的初始化过程,也就是对象怎么产生,怎么初始化得到的。

​ 首先介绍一下 Date 类,这个类是 Java 标准库的一个类(注意是java.util.Date路径),已经由 Java 开发人员封装好的一个类,在实际开发中,我们使用的它的次数也会比较多。Date 类的对象是描述一个具体的时间点,但时间点的表现形式可以不同,像某些地区时间形式习惯为(月/日/年),而国内更习惯(年/月/日)。

​ 大家应该知道,一个类的构造器名称和类是相同的,Date 类也是如此,当我们初始化 Date 类时调用的也是 Date()构造方法,在构造方法前加上 new 操作符,就成为了:new Date(),此时在堆内存中该新建的对象被赋予了当前时间,我们可以直接使用其作为参数传入方法内,如System.out.println(new Date());,也可将其赋值给一个对象变量,如Date birthday = new Date(); 此时 birthday 这个对象变量在内存中指向了新建的 Date 对象,

在这里插入图片描述

我们应该注意到,对象和对象变量的区别,对象变量不一定代表有指向的对象,例如我们只是定义了一个Date对象

变量Date birthdayB = null;,但没有指向(赋于)任何已存在的 Date 对象,那么我们此时是不能使用该对象变量,因为其并没有经过初始化或者指向任何已存在的 Date 对象。并且,对象变量仅仅只是引用了一个对象,并不是实际的对象;

​ 上面的Date birthday = new Date();语句表明,此时 birthday 对象变量已经引用了具体的Date对象,当使用System.out.println(birthday);输出时会有Sat Sep 05 10:30:31 CST 2020(中国东八区标准时间),会发现这个输出的日期是让我们不太习惯,我们更习惯于2020-09-05 10:30:31表现形式,所以当使用 Date 类输出一定形式的时间时,需要进行格式转化:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date birthday = new Date();
System.out.println(birthday.toString());        //①  Sat Sep 05 10:32:59 CST 2020
System.out.println(birthday);                   //②  Sat Sep 05 10:32:59 CST 2020
System.out.println(System.currentTimeMillis()); //③  1599273179522
System.out.println(format.format(birthday));    //④  2020-09-05 10:32:59

上面四种输出方式:

​ ①和②输出结果是一样的,①是由birthday.toString()输出,因为Java 所有类都有一个公共的父类Object,toString方法是继承而来;

​ ③输出的是一串数字,这又是什么呢?System.currentTimeMillis()语句是获取从 1970年1月1日 00:00:00到此刻的时间毫秒值;

​ ④输出的是经过SimpleDateFormat类格式化后得到一种时间表现形式,当然日期格式化方式很多,这里暂不做考究;

3.自定义类

3.1 实例域和静态域

package study.pojo;

import java.util.Date;

public class DogDemo {
    public static final String CLASSIFICATION_OF_ANIMALS = "狗";//①动物分类——狗(静态域)

    private final String name;//②名字(实例域)

    private static int id = 1;//③ID 号(静态域)

    private Date birthday;//④出生日期(实例域)

    {//⑤(实例域)
        System.out.println("输出语句:打印非静态代码块");
    }

    static {//⑥(静态域)
        System.out.println("输出语句:打印静态代码块");
    }

    public static void staticMethod() {//⑦(静态域)
        System.out.println("静态方法");
    }

    public void exampleMethod() {//⑧(实例域)
        System.out.println("实例方法");
    }

    public void printDogInfo(){//⑨打印小狗信息(实例域)
        System.out.println(DogDemo.CLASSIFICATION_OF_ANIMALS+":"+name+"的ID 是"+id+",它的出生日期是:"+birthday);
    }

    public DogDemo(String name) {//构造器①(参数 name)
        this.name = name;
    }

    public DogDemo(String name, Date birthday) {//构造器②(参数1 name,参数 2 birthday)
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {//参数 name get方法
        return name;
    }

    public static int getId() {//参数 name get方法
        return id++;
    }

    public Date getBirthday() {//参数 name get方法
        return birthday;
    }

    public void setBirthday(Date birthday) {//参数 name get方法
        this.birthday = birthday;
    }
}

上面是自定义的一个动物——dog 类,当我们使用测试类 main 方法调用下面语句时:

public static void main(String[] args) {
    DogDemo tangMu = new DogDemo("汤姆");
    // 输出语句:打印静态代码块
    // 输出语句:打印非静态代码块
}

这个时候只是新建了 DogDemo 类,但可以发现,调用的是一个带参数name的构造器,并且只是 new 了一个对象,但是在控制台有输出值,有以下几点原因:

(1)final 修饰静态常量和非静态变量

​ 在自定义DogDemo类中,非静态name 被 final 修饰,静态常量CLASSIFICATION_OF_ANIMALS被 fianl 修饰。当非静态成员变量用 final 修饰时,需要在定义时赋值或者使用构造器赋值,并且被赋值后不可再被更改,也就是 final 修饰的变量只可被一次赋值;当静态成员常量被 final 时,需要在定义时赋值,如private static final String CLASSIFICATION_OF_ANIMALS = "狗";

关于 final 修饰的非静态变量,赋值方式总结如下:

​ ①定义时赋值:private final String name = "汤姆";在本类中,final修饰的是 name,因每个小狗姓名可能不同,我们就不能在定义时赋值;

​ ②在构造器内赋值,无需传入参数:

public DogDemo() {
    this.name = "汤姆";
}

​ ③构造器传参数进行初始化:

public DogDemo(String name) {//构造器①(参数 name)
    this.name = name;
}

​ ④代码块中进行初始化,当使用代码块初始化,那就无需再通过构造器初始化,final 修饰的变量只需初始化一次:

{//⑥(实例域)
    System.out.println("输出语句:打印非静态代码块");
    name="汤姆";
}
(2)静态代码块和非静态代码块

​ 在自定义DogDemo类中,静态代码块属于静态域,非静态代码块属于实例域,可以看到在自定义类中,非静态代码块在静态代码块前面,但是打印时,先打印的是静态代码块输出语句,这是为什么呢?因为静态代码块是当一个类加载时就初始化了,且只初始化一次,不会因为每次对象创建而创建,而非静态代码块随着每次对象的创建都会初始化一次,如下两个对象一个加载时出现的情况:

public static void main(String[] args) {
        DogDemo tangMu = new DogDemo("小汤姆");

        DogDemo jieMu = new DogDemo("小杰姆");
        // 输出语句:打印静态代码块
        // 输出语句:打印非静态代码块
        // 输出语句:打印非静态代码块
}

说明静态代码块只打印了一次,并没有因为有两个对象的创建而创建两次。

(3)静态方法和实例方法

​ 在自定义类中,静态方法有staticMethod() 方法,实例方法有exampleMethod()和printDogInfo(),还是老样子,静态域属于类本身,实例属于对象,当调用时,静态方法调用格式为:类名.静态方法名(参数列表)。实例方法:类对象.实例方法名(参数列表)。

    public static void main(String[] args) {
        DogDemo tangMu = new DogDemo("小汤姆");

        tangMu.exampleMethod();
        DogDemo.staticMethod();
        // 输出语句:打印静态代码块
        // 输出语句:打印非静态代码块
        // 实例方法
        // 静态方法
    }

3.2 构造方法

(1)构造方法重载

在自定义DogDemo类中,定义了两个构造器:

public DogDemo(String name) {//构造器①(参数 name)
    this.name = name;
}

public DogDemo(String name, Date birthday) {//构造器②(参数1 name,参数 2 birthday)
    this.name = name;
    this.birthday = birthday;
}

调用两种构造器时:

DogDemo tangMu = new DogDemo("小汤姆");
DogDemo jieMu = new DogDemo("小杰姆",new Date());

往回看两个构造方法,会发现两个方法名相同,且都是类名,它们区别是传入的参数不同,构造器①需要传入参数是name,构造器②需要传入参数name 和 birthday。按照 Java 重载的定义,一个类中出现两个或多个具有相同方法名,标签它们的参数列表不同,那么这些方法产生了重载,需要注意:参数列表不同可以是参数的个数、顺序等不同,并且重载的定义和方法的返回值无关。

(2)无参构造

自定义DogDemo类没有看到无参构造,是因为该类中存在未初始化定义的非静态变量 name需要在构造器传入初始化值。但是,在 Java 中,自动一类如果没有编写构造方法,那么系统会给该类默认提供一个无参构造器,并且对未初始化变量进行复制,其中,数值型设置为 0,布尔值设置为 false,所有对象变量设置为 null。如果删除 name 变量或者先定义 name 初始值,那么该类存在的无参构造方法为:

public DogDemo() {
}

4.类设计技巧

(1)保证数据私有;

(2)数据尽量要初始化,不依赖 Java 默认初始值;

(3)不要在类中过多使用基本类型;

(4)不是所有的域都需要独立的域访问器或域更改器;

(5)将职责过多的类分解;

(6)类名和方法名要体现它们的职责;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值