Java 类基础

Wafer Li ... 2017-03-16 Java
  • Java
  • 语言之路
大约 5 分钟

# 1. 概述

△Java语言就是基于类的语言,许多术语与C++稍有区别

C++ Java
函数 方法
构造函数 构造器
析构函数 析构器
类中的数据 实例域
静态数据 静态域

例如 String a; C++ 称 String 为类,而 a 为对象,C++ 在此时就分配了内存,构建了对象 Java 称 String 为类,a 为引用,而当使用 new 请求,分配了空间,构建出的数据块称为对象

类对象必须使用new来构建,单纯的声明类仅仅只是声明了类的引用,并没有分配空间

# 2. 自定义类

  1. 一个源文件只能拥有一个 public 类,且必须与文件名一致

    通过在类的 class 前缀上 public 获得这一特性

    包含 main() 方法的类才能成为启动类,每个类都可以拥有 main()方法 通常用作类的普通测试

  2. Java不支持析构函数,反之,会自动进行垃圾回收

  3. 所有的方法都要在类的内部进行定义

    实际上,任何一个Java程序都是从类开始的

  4. 如果需要返回一个可变对象的引用,应该对其进行克隆(clone)

    ※这是由于变量都是一个指向对象的“类似指针的”引用,有可能会使得数据封装性遭到破坏

  5. final 修饰符在使用时大多应用于不可修改的类,当应用在可变的类的时候,并不意味着类的内容不可修改

    class Employee
    {
        private final String name;
    	private final Date hiredate: 2017-03-16
    }
    
    /**
    * 此时,name引用和对象都不能被修改【String类是不可变的类】
    * hiredate: 2017-03-16
    * 这里的hiredate: 2017-03-16
    */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  6. 通过 static 声明静态域和静态方法

  • 静态域和 C++ 类中的静态变量没有什么区别

  • 静态公有常量可以通过类名来直接调用,由于有 final 限制,所以不会造成封装性破坏

    如Math.PI就是一个静态公有变量

    其实也可以通过对象引用来调用,不过一般通过类名调用使得易读性更强

    静态方法可以通过类名和对象引用直接调用,但一般使用类名调用增强易读性 如 Math.pow(x,y)

  • 静态方法只能对对象静态域实施操作,而不能对实例域实施操作

  • 通常只有在接受外来参数和调用静态域的时候才使用静态方法

  1. 对象的构造

    1. 可以直接在构造器内初始化实例域,即使是包含关系

    2. 通过使用this来实现传参和实例域同名,甚至调用另一个构造器

      public Class(String name, double salary)
      {
          this.name = name;
      	this.salary = salary;
      }
      
      public Class(double s)
      {
          this("Class * " + nextId, s);
          nextId++;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
    3. 默认将所有数值初始化为0,布尔值初始化为false,引用初始化为null

      如果没有提供显式构造器,则系统自动生成隐式(无参)构造器完成上述工作

      如果提供了显式构造器,则系统将不再自动生成无参构造器,上述操作将被视为非法

    4. 初始化块

      ※这个不常用,通常使用构造器完成工作 可以使用一个代码块对实例域进行初始化操作

      class Class
      {
          private int id;
          ....
      
          {
              id  = 1;
          }
      
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10

      初始化块在所有构造器执行之前执行。 通过标记关键字static可以对静态域进行初始化块操作

      static
      {
          id = 1;
      }
      
      1
      2
      3
      4
  2. 类的基本结构

  • 数据域
  • 构造器(constructor)
    • 访问器(getter)
    • 更改器(setter)

# 3. 方法参数

  1. Java总是按值传参,对象引用也是一个值

  2. 方法不能修改传递给它的实参

  3. 方法可以通过调用传入对象引用的对象的方法,实现对对象的修改

  4. 方法不能让对象参数引用一个新的对象

  5. 方法能够直接访问和修改相同类作为参数的对象实例的私有域

    class Foo {
        private String text;
    
        public void doStuff(Foo f) {
            System.out.println(f.text);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7

# 4. 包(package

※类似于C++的名称空间

  • 通过import语句来导入Java包

  • 添加static指令可以直接导入静态方法和静态域,使用的时候就无需使用类名来调用【UnRecommended】

  • 通过使用包名来具体访问一个类

  • 通过package语句来将类放入包中,通常在开头加入

    package com.myapp.corejava;
    
    1

    注意包名的命名要与目录树相匹配,即上述类文件必须位于 com/myapp/corejava 中,否则,最终的程序将无法运行

  • 包作用域

    • 如果实例域没有指定访问控制符,则这一个部分可以被同一个包的所有方法访问

      在编写类的时候,必须为实例域添加上访问控制符

  • 类路径(※好像只有使用Shell编译才会遇到这个问题?)

  • javadoc文档注释

    • /** 开头,以 */ 结尾
    • 可以使用 HTML 修饰符
    • 还有各种注释,这里不一一说明

# 5. 类设计技巧

  1. 保证数据私有

  2. 一定要对数据初始化,可以直接提供默认值,也可以在构造器中提供

  3. 不要在类中使用过多的基本类型,可以通过一个封装类来减少使用

    private String street;
    private String city;
    private String state;
    
    1
    2
    3

    这个可以通过一个 Address 类来解决

  4. 并不是所有的数据都需要访问器和更改器

  5. 将职责过多的类进行分解

    如果一个类能被拆分成两个或者多个独立的概念,那就进行拆分 注意这里是概念的拆分,而不是单纯将方法拆分

  6. 类名和方法名要能够体现它们的职责

    类名常用一个名词或者有定语修饰的名词 访问器使用小写的get开头 更改器使用小写的set开头