Chapter 4 对象与类


作者:Denis

版本:1.0

编写时间:2022/10/15

编写地点:中国山西省

4.1 类与对象的概述


可以把类想象为一个模具,利用类能够创造出很多同属于一个物种但参数不同的对象。

对象应该具有封装内部细节的特点,使对象的内部状态不能轻易地被他人所修改,同时也应该暴露出一些公共的接口,方便其他类的对象对其进行操作。

类也应该具备继承性,用户在编写新的类的时候,可以直接参考过往代码,而无需重复造轮子。

类之间的关系

  1. 依赖(uses-a)

最常见的一种关系,如果一个类的方法需要对另一个类的对象进行操作,就称一个类依赖另一个类,应该尽量减少这种依赖关系,即降低耦合度。

  1. 聚合(has-a)

一个类的内部实例字段包含另一个类的对象,即为聚合。

  1. 继承(is-a)

表示一种特殊与一般的关系,如果经理类继承员工类,那么经理就是一种特殊的员工。他与普通员工的大多数参数和行为一样,但也有其自己的参数和行为,如奖金,任免权。

4.2 LocalDate类


可以使用Date类来获取时间和日期,但为了分工明确,现在Date类被用作获取时间

获取日历就用LocalDate类

使用静态工厂方法获取LocalDate类的对象

LocalDate now = LocalDate.now();

或者使用LocalDate类的静态方法获取指定日期的对象

LocalDate nationalDay = LocalDate.of(1999, 10, 1);

一旦拥有这个对象,就可以用getYeargetMonthValuegetDayOfMonth获取该对象的年、月、日

plusDays方法可以为指定的日期添加任意的天数,并返回一个新的对象,而原来的对象不做任何改动。

import java.time.LocalDate;

public class LocalDateTest {

    public static void main(String[] args) {
        LocalDate today = LocalDate.now();
        //可以看到,today并没有受到影响
        LocalDate aThousandDaysLater = today.plusDays(1000);
        System.out.println(today);
        System.out.println(aThousandDaysLater);
    }
}
//输出
2022-10-14
2025-07-10

LocalDate的其他方法

方法 返回类型 描述
getDayOfYear int 返回当前对象是一年中的第几天
getDayOfWeek DayOfWeek 返回一个DayOfWeek对象,使用其getValue方法获取当前对象是星期几
minusDays(int n) LocalDate 当前对象之前n天的日期

4.3 字段修饰符


访问修饰符可以对成员方法或者类字段进行修饰,也可以对类进行修饰。

对类进行修饰时,只能使用public和默认修饰符。

访问符 本类 包内 子类 外部类
public
protected
默认
private

有一种特殊情况,假如一个对象拥有私有字段,当其作为参数时,所属类的方法可以访问到这些私有字段

public class Employee{
    private String name;
    public boolean equals(Employee other){
        return this.name.equals(other.name);
    }
}

如果希望一个字段在设置后就不能被修改,可以设置为final

为字段添加final修饰后,必须在构造的时候就进行初始化操作

public class Employee{
    private final String name;
}

final修饰的字段对于基本类型和不可变类的对象非常有效,final修饰的字段只保证指向当前对象,不保证当前对象是否会被修改,例如StringBuilder

静态字段与静态方法

当字段或方法被static修饰,则该类的每个对象共同拥有同一个字段和方法

所以也被称为类变量,类方法

public class Employee{
    private String name;
    public static int nextId = 1;
}

由于公共变量会被随意修改,最好使用公共常量。典型的公共常量是System.out

静态方法没有隐式参数this,所以它不能访问对象的实例字段(除非该类的另一个对象作为参数),但可以访问该类的静态字段

静态方法的使用场景:

  • 不需要访问对象状态,所有参数显式提供
  • 只需要访问类的静态字段
  • 可以作为工厂方法,返回一个对象,例如LocalDate.now()。使用工厂方法可以返回不同状态、不同类型的对象。例如返回一个类的子类对象,而构造器无法实现这个功能。下面是一个使用工厂方法的例子。
import java.text.NumberFormat;

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

4.4 null引用


为一个引用变量赋值为null意味着当前变量没有指向任何对象,如果使用该变量调用成员方法,会出现空指针异常。

可以采取一种“宽容”的做法,即当判断一个变量为null时,给予一个默认值。

name = n == null ? "unknown" : n;

在Java9中,Objects类提供了一个便利的做法,逻辑与上述一致

public static <T> T requireNonNullElse(T obj, T defaultObj) {
	return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
}

如果采取严格的做法,拒绝接受null参数,可以采用另一个方法requireNonNull,他的第二个参数可以输出错误的信息。

使用这种方法有两种好处:可以告知问题出现的位置,便于排查

public static <T> T requireNonNull(T obj, String message) {
    if (obj == null)
    	throw new NullPointerException(message);
    return obj;
}

Objects类的其他方法

方法 描述
T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) obj不为null返回obj,否则返回默认对象
T requireNonNull(T obj, Supplier< String > messageSupplier) obj不为null返回obj,否则利用供应者以懒方式得到一个值

4.5 创建对象流程


  1. 先在方法区加载类信息
  2. 在堆中创建对象,分配空间,对基本类型置默认值,对引用类型置null
  3. 如果调用了另一个构造器(this(...)),先执行那个构造器
  4. 执行类的默认信息
  5. 执行类的初始化块
 public class Person{   
     //类的默认信息
 	 private String name = "xxx"; 
     public final static String company;
     //执行类的初始化块, 可以初始化任何变量,建议放在声明的字段之后
     {
        name = "李白";
     }
     //静态初始化块,只能初始化静态变量
     static{
      	company = "sx"; 
     }
 }
  1. 执行构造器,对对象进行初始化,对于构造器里的字符串,放在常量池进行引用。

下面是一个完整的案例

import java.util.*;

public class ConstructorTest
{
   public static void main(String[] args)
   {
      // fill the staff array with three Employee objects
      var staff = new Employee[3];

      staff[0] = new Employee("Harry", 40000);
      staff[1] = new Employee(60000);
      staff[2] = new Employee();

      // print out information about all Employee objects
      for (Employee e : staff)
         System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
            + e.getSalary());
   }
}

class Employee
{
   private static int nextId;

   private int id;
   private String name = ""; // instance field initialization
   private double salary;
  
   // static initialization block
   static
   {
      var generator = new Random();
      // set nextId to a random number between 0 and 9999
      // 这是创建随机数的第二种方法,第一种Math类的方法
      nextId = generator.nextInt(10000);
   }

   // object initialization block
   {
      id = nextId;
      nextId++;
   }

   // three overloaded constructors
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }

   public Employee(double s)
   {
      // calls the Employee(String, double) constructor
      this("Employee #" + nextId, s);
   }

   // the default constructor
   public Employee()
   {
      // name initialized to ""--see above
      // salary not explicitly set--initialized to 0
      // id initialized in initialization block
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public int getId()
   {
      return id;
   }
}

4.6 静态导入


可以使用import static语句来导入静态方法和静态字段,例如

import static java.lang.System.*

就可以使用System类的所以静态成员和静态方法,而无需添加前缀System

out.println("ok");
exit(0);

4.7 JAR文件


JAR文件把类文件和其所在的目录打包在一起,既可以节省空间又可以改善性能。可以使用ZIP工具查看JAR文件

JAR文件也可以有其他类型文件,如声音和图像

为了让编写的类可以在任意位置运行,需要进行如下设置

  • 使用java -classpath .;d:\archives;d:\jars\xxx.jar MyProg来启动MyProg程序,将自动从类路径搜索类
  • 也可以通过设置CLASSPATH环境变量临时指定一些目录,如set CLASSPATH=.;d:\archives;d:\jars\xxx.jar
  • 上述设置classpath都是临时的,一旦退出控制台,就需要再次输入指令
  • 永久设置CLASSPATH的方式是设置一个环境变量

创建JAR文件

命令为:jar cvf jarFileName file1 file2...

参数c为创建归档文件、v为输出详细的生成结果、f指定第一个参数为jar文件名,而非要压缩的文件,另外如果把c改为x是解压操作

清单文件 MANIFEST.MF

生成jar包时,包含一个清单文件,位于META-INF目录中。用户也可以添加自己编写的清单文件

可执行的JAR文件

命令为:jar cvfe jarFileName com.xxx.MainApp add files,在指定主类后,还需要在后面把主类添加进去

或者在清单文件中指定Main-Class

Manifest-Version: 1.0
Created-By: 11.0.15 (Oracle Corporation)
Main-Class: Welcome

执行jar文件,使用命令java -jar xxx.jar

还可以使用开源或者商业软件将jar变为exe文件

多版本的jar文件

随着Java版本的发行,可能对安装不同版本虚拟机的用户提供不同版本的Java程序

提供多版本jar文件的前提是,所有类的公共API是一样的,否则应该独立提供

在一个jar包内可以包含多个不同版本的Java程序,只需要将其放在META-INF/versions中即可。【since Java 9】

更新一个jar文件,使其支持多版本

命令:jar uf MyProgram.jar --release 9 Application.class

如果需要从头构建,应该使用-C选项,切换不同的目录

命令:jar cf MyProgram.jar -C bin/8 --release 9 -C bin/9 Application.class

对不同版本的文件进行编译时,需要使用-d选项指定输出目录

javac -d bin/8 --release 8 ...【release标志只能在Java 9或之后的版本使用】

原文地址:http://www.cnblogs.com/run-bit/p/16794692.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性