【学习笔记】Java基础知识点——第3章·对象与类

第3章  对象与类

3.1  面对过程和面对对象的区别

“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想,简称 OP。就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。所以面向过程的编程方式关注点不在“事物”上,而是做这件事分几步,先做什么,后做什么。例如:早晨起来:起床、穿衣、洗漱、上班,只要按照这个步骤来,就能实现“一天”的功能,整个这个过程中关注的是一步一步怎么做,并没有关注“人”这个事物。

“面向对象”(Object Oriented)是一种以对象为中心的编程思想,简称 OO。通过面向对象的方式,将现实世界的事物抽象成对象。通过面向对象的方法,更利于用人理解的方式对复杂系统进行分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,可以像搭积木的一样快速开发出一个全新的系统。面向对象将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

假如说编写一段程序,模拟一个人抽烟的场景,采用面向对象的方式关注点就不一样了,我们会想这个场景都有什么事物参与,每个事物应该有什么行为,然后将这些事物组合在一起,来描述这个场景,例如:一个会抽烟的人(对象)+香烟(对象)+打火机(对象)+允许抽烟的场所(对象),将以上 4 个对象组合在一起,就实现了抽烟场景,其中采用面向对象的方式开发具有很强的扩展力。

3.2  面对对象三大特征

面对对象具有三大特征:①封装;②继承;③多态

3.3  类

类是现实世界当中具有共同特征的事物进行抽象形成的模板或概念。而对象是实际存在的个体。

通过类可以创建对象,对象又被称为实例,通过类这个模板创建对象的过程,叫实例化;对象到类称为抽象。

其中实例变量、类变量、常量都是属于成员变量的,成员变量又被称为全局变量。

类 = 属性 + 方法,而属性描述的是状态,方法描述的是行为动作。行为动作以方法的形式存在,对象的属性以变量形式存在,并且这里的变量是“成员变量当中的实例变量”。

当类中的实例变量 没有手动赋值,在创建对象的时候,也就是说在 new 的时候,系统会对实例变量默认赋值。

3.3.1 类之间的关系

在类之间,最常见的关系有:

·依赖(“users-a”);

·聚合(“has-a”);

·继承(“is-a”)

依赖,即“users-a”关系,是一种最明显的、最常见的关系。如果一个类的方法使用或操纵另一个类的对象,我们就说一个类依赖于另一个类。应尽可能减少类之间的耦合。

聚合,即“has-a”关系。包容关系意味着类A的对象包含类B的对象。

继承,即“is-a”关系,表示一个更特殊的类与一个更一般的类之间的关系

3.3.2 使用预定义类

1.对象与对象变量

在Java语言中,要是用构造器(constructor,或称构造函数)构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。构造器的名字应该与类名相同。因此Date类的构造器名为Date。要想构造一个Date对象,需要在构造器前面加上new操作符,如下所示:

new Date();

在对象与对象变量之间存在着一个重要的区别。例如:

Date deadline;

定义了一个对象变量deadline,它可以引用Date类型的对象。但是,一定要认识到:变量deadline不是一个对象,而且事实上它也没有引用任何对象。此时还不能在这个变量上使用任何Date方法。必须首先初始化变量deadline,这里有两个选择。当然,可以初始化这个变量,让它引用一个新构造的对象:

deadline = new Date();

也可以设置这个变量,让它引用一个已有的对象。

在Java中,任何对象变量的值都是对存储在另外一个地方的某个对象的引用。new操作符的返回值也是一个引用。

2.Java类库中的LocalDate类

库类设计者决定将保存时间与给时间点命名分开。所以精准Java库类分别包含了两个类:一个是用来表示时间点的Date类;另一个是用日历表示法表示日期的LocalDate类。

不要使用构造器来构造LocalDate类的对象,实际上,应使用静态工厂方法(factory method),它会代表你调用构造器。

LocalDate.now();

可以提供年、月和日来构造对应一个特定的日期的对象:

LocalDate newYearsEve = LocalDate.of(1999,12,31);

一旦有了一个LocalDate对象,可以用方法getYear、getMonthValue和getDayOfMonth得到年、月和日。

例如,plusDays方法会得到一个新的LocalDate,如果把应用这个方法的对象称为当前对象,这个新日期对象则是距离当前对象指定天数的一个新日期:

LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);
year = aThousandDaysLater.getYear(); //2002
month = aThousandDaysLater.getMonthValue(); //09
day = aThousandDaysLater.getDayOfMonth(); //26

这个调用之后newYearsEve并不会改为1000天之后的日期。plusDays方法会生成一个新的LocalDate对象,然后把这个新对象赋给aThousandDaysLater变量。原来的对象不做任何改动。我们说plusDays方法没有更改调用这个方法的对象。(这类似于String类的toUpperCase方法。在一个字符串上调用toUpperCase时,这个字符串仍保持不变,会返回一个将字符大写的新字符串。)

3.3.3 用户自定义类

1.使用null引用

如果对null值应用一个方法,会产生一个NullPointerException异常。如果你的程序没有“捕获”异常,程序就会终止。正常情况下,程序并不捕获这些异常,而是依赖于程序员从一开始就不要带来异常。

在Java9中,Objects类对此提供了一个便利方法:

public Employee(String n, double s, int year, int month, int day){
    name = Object.requireNonNullElse(n,”unknown”);
}

“严格型”方法则是干脆拒绝null参数:

public Employee(String n, double s, int year, int month, int day){
    name = Object.requireNonNull(n,”名字不能为空”);
}

如果有人用一个null名字构造了一个Employee对象,就会产生NullPointerException异常。

2.隐式参数和显式参数

显式参数显式地列在方法声明中;隐式参数没有出现在方法声明中。在每一个方法中,关键字this指示隐式参数。

3.final实例字段

可以将实例字段定义为final。这样的字段必须在构造对象时初始化。对于可变的类,使用final修饰符可能会造成混乱。例如,考虑以下字段:

public class FinalTest {

    private final StringBuilder evaluations = new StringBuilder();

    public void giveGoldStar(){
        evaluations.append(LocalDate.now());
        System.out.println("evaluations = " + evaluations + ",hash值:" + evaluations.hashCode());
    }

    public static void main(String[] args) {
        FinalTest test = new FinalTest();
        test.giveGoldStar();    //evaluations = 2021-07-31,hash值:1480010240
        test.giveGoldStar();    //evaluations = 2021-07-312021-07-31,hash值:1480010240
    }
}

final关键字只是表示存储在evaluations变量中的对象引用不会再指示另一个不同的StringBuilder对象。不过这个对象可更改。

3.4  对象创建和使用

3.4.1 对象

对象的三个主要特性:

  • 对象的行为——可以对对象完成哪些操作,或者可以对对象应用哪些方法?
  • 对象的状态——当调用哪些方法时,对象会如何响应?
  • 对象的标识——如何区分具有相同行为与状态的不同的对象?

同一个类的所有对象实例,由于支持相同的行为而具有家族式的相似性。对象的行为是用可调用的方法来定义的。

每个对象都保存着描述当前状态的信息。这就是对象的状态。对象的状态可能会随着时间而发生改变,但这种改变不会是自发的。对象状态的改变必须通过调用方法实现(如果不经过方法调用就可以改变对象状态,只能说明破坏了封装性)。

但是对象的状态并不能完全描述一个对象。每个对象都有一个唯一的标识。需要注意,作为同一个类的实例,每个对象的标识总是不同的,状态也往往存在着差异。

3.4.2 Java虚拟机内存管理

1.程序计数器:

  • 概念:可以看做当前线程所执行的字节码的行号指示器。
  • 特点:线程私有的内存。

2.java 虚拟机栈(重点):

  • 概念:描述的是 java 方法执行的内存模型。(每个方法在执行的时候会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直至完成的过程,就对应一个栈帧从入栈到出栈的过程)
  • 特点:线程私有,生命周期和线程相同。

3.本地方法栈:

  • 概念:它与虚拟机栈所发挥的作用是相似的,区别是 java 虚拟机栈为执行 java 方法服务,而本地方法栈是为本地方法服务。
  •  特点:线程私有。

4.java 堆(重点):

  • 概念:是被所有线程共享的一块区域,在虚拟机启动时创建。
  • 特点:线程共享,存放的是对象实例(所有的对象实例和数组),GC 管理的主要区域。可以处于物理上不连续的内存空间。

5.方法区(重点):

  • 概念:存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代码等数据。
  • 特点:线程共享的区域。

针对于目前来说,要知道 java 虚拟机有三块主要的内存空间,分别是“虚拟机栈(简称栈)”、“方法区”、“堆区”。

方法区存储类的信息;栈中存储方法执行时的栈帧以及局部变量;堆区中主要存储 new 出来的对象,以及对象内部的实例变量。其中垃圾回收器主要针对的是堆内存,方法区中最先有数据,因为程序执行之前会先进行类加载。栈内存活动最频繁,因为方法不断的执行并结束,不断的进行压栈弹栈操作。

将目前阶段需要掌握的内存空间使用一张简单的图表示出来,这个图是需要掌握的:

public class StudentTest {
    public static void main(String[] args) {
        int i = 10;
        Student s1 = new Student();
        Student s2 = new Student(100, yth, 30, true);
    } 
}

以上代码在执行过程中内存的变化如下:

上图堆区中“对象”创建完成之后,该对象在堆区当中的内存地址是:0x1234,程序中的 “=”将 0x1234这个堆内存地址赋值给 s1 变量,也就是说 s1 变量保存了堆内存对象的内存地址,我们对于这种变量有一种特殊的称呼,叫做“引用”。也就是说对于 Student s1 = new Student();代码来说,s1 不是对象,是一个引用,对象实际上是在堆区当中,s1 变量持有这个对象的内存地址。

能通过“引用”去访问堆内存中的对象,例如:s1.no……访问一个对象的内存,其实就是访问该对象的实例变量,而访问实例变量通常包括两种形式,要么就是读取数据,要么就是修改数据,例如:System.out.println(s1.no);这就是读取数据,s1.no = 100 这就是修改数据。

3.4.3 构造方法Constructor

构造方法怎么定义,请看以下的语法格式:[修饰符列表] 构造方法名(形式参数列表){构造方法体; }

  • 构造方法名和类名一致。
  • 构造方法用来创建对象,以及完成属性初始化操作。
  • 构造方法的返回值类型实际上是当前类的类型。
  • 一个类中可以定义多个构造方法,这些构造方法构成方法重载。

构造方法虽然在返回值类型方面不写任何类型,但它执行结束之后实际上会返回该对象在堆内存当中的内存地址,这个时候可以定义变量接收对象的内存地址,这个变量就是“引用”。

构造方法的作用是专门用来创建对象同时给属性赋值的,因为构造方法名和类名一致,还不需要写返回值类型,使用 new 就可以调用了。在一个类当中可以同时定义多个构造方法,它们之间构成重载关系。这样就做到了在 java 中你想要什么就 new什么,每一次 new都会在堆内存中创建对象,并且对象内部的实例变量被初始化了。

一定要注意,实例变量没有手动赋值的时候系统会默认赋值,但不管是手动赋值还是系统赋默认值,都是在构造方法执行的时候才会进行赋值操作,类加载的时候并不会初始化实例变量的空间,那是因为实例变量是对象级别的变量,没有对象,哪来实例变量,这也是为什么实例变量不能采用“类名”去访问的原因。

 通过上图可以看到,Student对象当中的name 这个“属性/实例变量”是一个引用,保存的不是”yth”字符串,而是字符串对象的内存地址。(实际上,字符串”yth”是在方法区的字符串常量池当中)。

3.4.4 方法调用时参数的传递问题

public class ParamTest02 {
    public static void main(String[] args) {
        int a = 10;
        int b = a;
        System.out.println(a==b);//true
        Bird bird1 = new Bird("polly");
        Bird bird2 = bird1;
        System.out.println(bird1.hashCode());//2003749087
        System.out.println(bird2.hashCode());//2003749087
    }
}
class Bird{
    private String name;
    public Bird(String name){this.name = name;}
}

3.4.5 显式字段初始化

通过重载类的构造器方法,可以采用多种形式设置类的实例字段的初始状态。不管怎样调用构造器,每个实例字段都要设置为一个有意义的初值,确保这一点总是一个好主意。

可以在类定义中直接为任何字段赋值,例如:

class Employee{
    private String name = "";
}

在执行构造器之前先完成这个赋值操作。如果一个类的所有构造器都希望把某个特定实例字段设置为同一个值,这个语法就特别有用。

初始值不一定是常量值。下面的例子中,就是利用方法调用初始化一个字段。考虑以下Employee类,其中每一个员工有一个ID字段。可以使用下列方式进行初始化:

class Employee{
    private static int nextId;
    private int id = assignId();
    private static int assignId(){
        int r = nextId;
        nextId++;
        return r;
    }
}

3.4.6 调用另一个构造器

如果构造器的一个语句形如:this(...),这个构造器将调用同一个类的另一个构造器。

3.4.7 初始化块

Java还有第三种机制,称为初始化块(initialization block)。在一个类的声明中,可以包含任意多个代码块。只要构造这个类的对象,这些块就会被执行。例如:

public class Employee {

    private static int nextID;
    private int ID;
    private String name;

    { //对象初始化块
        ID = nextID;
        nextID++;
    }

    public Employee(){}

    public Employee(int ID) {
        this(ID,"创建这个对象时的nextID:"+nextID);
    }

    public Employee(int ID, String name) {
        this.ID = ID;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "ID=" + ID +
                ", name='" + name + '\'' +
                ", nextID='" + nextID + '\'' +
                '}';
    }

    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee(2);
        Employee e3 = new Employee(3, "3号");
        Employee e4 = new Employee();
        System.out.println(e1); //Employee{ID=0, name='null', nextID='4'}
        System.out.println(e2); //Employee{ID=2, name='员工配nextID:1', nextID='4'}
        System.out.println(e3); //Employee{ID=3, name='3号', nextID='4'}
        System.out.println(e4); //Employee{ID=3, name='null', nextID='4'}
    }
}

3.4.8 Java中的三大变量

3.5  封装

封装是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。

封装之后就形成了独立实体,独立实体可以在不同的环境中重复使用,显然封装可以降低程序的耦合度,提高程序的扩展性,以及重用性或复用性。例如“鼠标”可以在 A 电脑上使用,也可以在 B 电脑上使用。另外封装可以隐藏内部实现细节,站在对象外部是看不到内部复杂结构的,对外只提供了简单的安全的操作入口,所以封装之后,实体更安全了。

3.5.1 实现封装

  • 使用 java 语言中的 private 修饰符,private 修饰的数据表示私有的,私有的数据只能在本类当中访问。
  • 对外提供公开的访问入口,让外部程序统一通过这个入口去访问数据,我们可以在这个入口处设立关卡,进行安全控制,这样对象内部的数据就安全了。通常情况下我们访问对象的某个属性,不外乎读取(get)和修改(set),所以对外提供的访问入口应该有两个。

3.6  this

3.6.1 this是什么

this 可以看做一个变量,它是一个引用,存储在 Java 虚拟机堆内存的对象内部,this 这个引用保存了当前对象的内存地址指向自身,任何一个堆内存的 java 对象都有一个 this,也就是说创建 100 个 java 对象则分别对应 100 个 this。

3.6.2 this使用在实例方法中

this 可以出现在实例方法当中,因为实例方法在执行的时候一定是对象去触发的,实例方法一定是对象才能去调用的,而 this 恰巧又代表“当前对象”,所以“谁”去调用这个实例方法 this 就是“谁”。

this 不能出现在 static 的方法中,可以出现在实例方法中,代表当前对象,大部分情况下 this 都是可以省略的,只有当在实例方法中区分局部变量和实例变量的时候不能省略。

3.6.3 总结this的使用

  1. this是一个关键字,是一个引用,保存内存地址指向自身。
  2. this可以使用在实例方法中,也可以使用在构造方法中。
  3. this出现在实例方法中其实代表的是当前对象。
  4. this不能使用在静态方法中。
  5. “this.”大部分情况下可以省略,但是用来区分局部变量和实例变量的时候不能省略。
  6. this() 这种语法只能出现在构造方法第一行,表示当前构造方法调用本类其他的构造方法,目的是代码复用。

3.7  static

3.7.1 static概述

修饰的变量叫做静态变量,修饰的方法叫做静态方法,修饰的代码块叫做静态代码块。在 java语言中凡是用 static 修饰的都是类相关的,不需要创建对象,直接通过“类名”即可访问,即使使用“引用”去访问,在运行的时候也和堆内存当中的对象无关。

3.7.2 静态变量

“男人类”创建的所有“男人对象”,每一个“男人对象”的身份证号都不一样,该属性应该每个对象持有一份,所以应该定义为实例变量,而每一个“男人对象”的性别都是“男”,不会随着对象的改变而变化,性别值永远都是“男”,这种情况下,性别这个变量再定义为实例变量浪费了大量的堆内存空间,所以这个时候建议将“性别=男”属性定义为类级别的属性,声明为静态变量,上升为“整个族”的数据,这样的变量不需要创建对象直接使用“类名”即可访问。

当一个类的所有对象的某个“属性值”不会随着对象的改变而变化的时候,建议将该属性定义为静态属性(或者说把这个变量定义为静态变量),静态变量在类加载的时候初始化,存储在方法区当中,不需要创建对象,直接通过“类名”来访问。

3.7.3 静态代码块

静态代码块的语法格式是这样的:

类{
    //静态代码块
    static{
        //java 语句;
    }
}

静态代码块在类加载时执行,并且只执行一次。开发中使用不多,但离了它有的时候还真是没法写代码。静态代码块实际上是 java 语言为程序员准备的一个特殊的时刻,这个时刻就是类加载时刻,如果你想在类加载的时候执行一段代码,那么这段代码就有用了。

静态代码块遵循自上而下的顺序依次执行,所以有的时候放在类体当中的代码是有执行顺序的(大部分情况下类体当中的代码没有顺序要求,方法体当中的代码是有顺序要求的,方法体当中的代码必须遵守自上而下的顺序依次逐行执行),另外静态代码块当中的代码在 main 方法执行之前执行,这是因为静态代码块在类加载时执行,并且只执行一次。

3.7.4 静态方法

实例方法中才有 this,静态方法中不存在 this。

在下面两种情况下可以使用静态方法:

  • 方法不需要访问对象状态,因为它需要的所有参数都通过显式参数提供(例如:Math.pow)。
  • 方法只需要访问类的静态字段。

3.7.5 工厂方法

类似LocalDate和NumberFormat的类使用静态工厂方法(factory method)来构造对象。比如LocalDate.now和LocalDate.of。NumberFormat类如下生成不同风格的格式化对象:

public class FactoryMethod {
    public static void main(String[] args) {
        NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
        NumberFormat percentFormatter = NumberFormat.getPercentInstance();
        double x = 0.1;
        System.out.println(currencyFormatter.format(x));	//结果输出:¥0.10
        System.out.println(percentFormatter.format(x));	    //结果输出:10%
    }
}

为什么NumberFormat类不利用构造器完成这些操作呢?这主要有两个原因:

  • 无法命名构造器。构造器的名字必须与类相同。但是,这里希望有两个不同的名字,分别得到货币实例和百分比实例。
  • 使用构造器时,无法改变所构造对象的类型。而工厂方法实际上将返回DecimalFormat类的对象,这是NumberFormat的一个子类。

3.7.6 main方法

每个类可以有一个main方法。这是常用于对类进行单元测试的一个技巧。事实上,在启动程序时还没有任何对象。静态的main方法将执行并构造程序所需要的对象。

3.8  方法参数

按值调用:表示方法接收的是调用者提供的值。

而按引用调用:表示方法接收的是调用者提供的变量地址。

方法可以修改按引用传递的变量的值,而不能修改按值传递的变量的值。Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个副本。具体来讲,方法不能修改传递给它的任何参数变量的内容。例如,考虑下面的调用:

public class ParamTest {

    public static double tripleValue(double x){
        x = 3 * x;
        return x;
    }

    public static void tripleSalary(Employee x){
        x.raiseSalary(200);
    }

    public static void swap(Employee x, Employee y){
        Employee temp = x;
        x = y;
        y = temp;
        System.out.println("交换过程中x = " + x.getName());//交换过程中x = Bob
        System.out.println("交换过程中y = " + y.getName());//交换过程中y = Alice
    }

    public static void main(String[] args) {

        /**
         * Test 1:方法不能修改数值参数
         */
        double percent = 10;
        System.out.println("Before:percent = "+percent);//Before:percent = 10.0
        tripleValue(percent);
        System.out.println("After:percent = "+percent + "\n");//After:percent = 10.0

        /**
         * Test 2:方法可以更改对象参数的状态
         */
        Employee harry = new Employee("Harry",50000);
        System.out.println("Before:salary = "+harry.getSalary());
        tripleSalary(harry);
        System.out.println("After:salary = "+harry.getSalary() + "\n");

        /**
         * Test 3:方法无法将新对象附加到对象参数
         */
        Employee a = new Employee("Alice",7000);
        Employee b = new Employee("Bob",6000);
        System.out.println("Before:a = "+a.getName());//Before:a = Alice
        System.out.println("Before:b = "+b.getName());//Before:b = Bob
        swap(a,b);
        System.out.println("After:a = "+a.getName());//Before:a = Alice
        System.out.println("After:b = "+b.getName());//Before:b = Bob
    }
}


class Employee{

    private String name;
    private double salary;

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public void raiseSalary(double byPercent){
        double raise = salary * byPercent / 100;
        salary += raise;
    }
}

你已经看到,一个方法不可能修改基本数据类型的参数,而对象引用作为参数就不同了实现一个改变对象参数状态的方法是完全可以的,实际上也相当常见。理由很简单,方法得到的是对象引用的副本,原来的对象引用和这个副本都引用同一个对象。

Java程序设计语言对对象采用的不是按引用调用,实际上,对象引用是按值(内存地址)传递的。

总结一下在Java中对方法参数能做什么和不能做什么:

  • 方法不能修改基本数据类型的参数(即数值型或布尔型)。
  • 方法可以改变对象参数的状态。

3.9  包

包其实就是目录,特别是项目比较大,java 文件特别多的情况下,我们应该分目录管理,在 java 中称为分包管理,包名称通常采用小写。包的命名应该有规则,不能重复,一般采用公司网站逆序,如:com.bjpowernode.项目名称.模块名称。

3.9.1 类的导入

在大多数情况下,可以只导入需要的包。但在发生命名冲突的时候,就要注意包了。例如,java.util和java.sql包都有Date类。如果在程序中导入了这两个包:

import java.util.*;
import java.sql.*;

在程序使用Date类的时候,就会出现一个编译错误:java.util.Date or java.sql.Date?

此时编译器无法确定想使用的是哪一个Date类。可以增加一个特定的import语句来解决这个问题:

import java.util.*;
import java.sql.*;
import java.util.Date;

如果这两个Date类都需要使用。在每个类名的前面加上完整的包名。

Date deadline = new java.util.Date();
Date today = new java.sql.Date(...);

在包中定位类是编译器的工作,类文件中的字节码总是使用完整的包名引用其他类。

3.9.2 静态导入

例如,如果在源文件顶部,添加一条指令,就可以使用System类的静态方法和静态字段,而不必加类名前缀:

import static java.lang.System.*;
out.println(“Goodbye,World!”);

3.9.3 JDK常用开发包

  • java.lang,此包 Java 语言标准包,使用此包中的内容无需 import 引入
  • java.sql,提供了 JDBC 接口类
  • java.util,提供了常用工具类
  • java.io,提供了各种输入输出流

3.9.4 访问控制权

  • 属性(4个都能用)
  • 方法(4个都能用)
  • 类(public和默认能用,其它不行。)
  • 接口(public和默认能用,其它不行。)

3.10  常用类

3.10.1 日期类

1.Date类

获取系统当前时间

Date d = new Date();    //Tue Jul 20 21:44:17 CST 2021

2.SimpleDateFormat

将日期类型Date,按照指定的格式进行转换:Date———>转换成具有一定格式的日期字符串——>String

SimpleDateFormat是java.text包下的。专门负责日期格式化的。

yyyy-MM-dd HH:mm:ss SSS,在日期格式中,除了y、M、d、H、m、s、S这些字符不能随便写之外,剩下的符号格式自己随意组织。

SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss SSS");
String s = sdf.format(new Date());	//2000-09-02 18:30:30 666

假设现在又一个日期字符串String,怎么转换成Date类型:

String time = “2008-08-08 08:08:08”;
SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(time);

获取从1970年1月1日00:00:00到当前系统时间的总毫秒数

long begin = System.currentTimeMillis();

3.10.2 数字类

DecimalFormat专门负责数字格式化。

  • #代表任意数字
  • ,代表千分位
  • .代表小数点
  • 0代表不够时补0
DecimalFormat df = new DecimalFormat(“###,###,##”);
String s = df.format(1234.5664465);	//1,234.56

3.10.3 随机数

创建随机数对象:

Random random = new Random();

随机产生一个int类型取值范围内的数字:

int num = random.nextInt(100);    //[0,99]

3.11  类设计技巧

  1. 一定要保证数据私有。
  2. 一定要对数据进行初始化。
  3. 不要在类中使用过多的基本类型。
  4. 不是所有的字段都需要单独的字段访问器和更改器。
  5. 分解有过多职责的类。
  6. 类名和方法名要能够体现他们的职责。
  7. 优先使用不可变的类。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值